int interface_superblock(disk_t *disk_car,list_part_t *list_part, char**current_cmd) { const list_part_t *parts; const partition_t *old_part=NULL; #ifdef HAVE_NCURSES struct MenuItem menuSuperblock[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q',"Quit","Return to Advanced menu"}, { 0, NULL, NULL } }; #endif screen_buffer_reset(); #ifdef HAVE_NCURSES aff_copy(stdscr); wmove(stdscr,4,0); wprintw(stdscr,"%s",disk_car->description(disk_car)); wmove(stdscr,5,0); mvwaddstr(stdscr,6,0,msg_PART_HEADER_LONG); #endif for(parts=list_part;parts!=NULL;parts=parts->next) { const partition_t *partition=parts->part; if(old_part==NULL || old_part->part_offset!=partition->part_offset || old_part->part_size!=partition->part_size || guid_cmp(old_part->part_type_gpt, partition->part_type_gpt)!=0 || old_part->part_type_i386!=partition->part_type_i386 || old_part->part_type_sun!=partition->part_type_sun || old_part->part_type_mac!=partition->part_type_mac || old_part->upart_type!=partition->upart_type) { aff_part_buffer(AFF_PART_BASE, disk_car, partition); old_part=partition; } if(partition->blocksize!=0) screen_buffer_add("superblock %lu, blocksize=%u [%s]\n", (long unsigned)(partition->sb_offset/partition->blocksize), partition->blocksize, partition->fsname); } if(list_part!=NULL) { const partition_t *partition=list_part->part; screen_buffer_add("\n"); screen_buffer_add("To repair the filesystem using alternate superblock, run\n"); screen_buffer_add("fsck.ext%u -p -b superblock -B blocksize device\n", (partition->upart_type==UP_EXT2?2: (partition->upart_type==UP_EXT3?3:4))); } screen_buffer_to_log(); if(*current_cmd==NULL) { log_flush(); #ifdef HAVE_NCURSES screen_buffer_display(stdscr,"",menuSuperblock); #endif } return 0; }
static void change_part_type_ncurses(const disk_t *disk_car,partition_t *partition) { partition_t *new_partition; char response[100]; int size=0; int i; unsigned int last[3], done = 0, next = 0; struct part_name_struct part_name[0x100]; struct MenuItem menuType[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q', "Proceed","Go set the partition type"}, { 0, NULL, NULL } }; if(partition->arch->set_part_type==NULL) return ; /* Create an index of all partition type except Intel extended */ new_partition=partition_new(NULL); dup_partition_t(new_partition,partition); for(i=0;i<=0xFF;i++) { if(partition->arch->set_part_type(new_partition,i)==0) { part_name[size].name=new_partition->arch->get_partition_typename(new_partition); if(part_name[size].name!=NULL) part_name[size++].index=i; } } free(new_partition); /* Display the list of partition type in 3 columns */ screen_buffer_reset(); screen_buffer_add("List of partition type\n"); for (i = 2; i >= 0; i--) last[2 - i] = done += (size + i - done) / (i + 1); i = done = 0; while (done < last[0]) { screen_buffer_add( "%02x %-20s%c", part_name[next].index, part_name[next].name,(i==2 ? '\n' : ' ')); next = last[i++] + done; if (i > 2 || next >= last[i]) { i = 0; next = ++done; } } /* Ask for the new partition type*/ aff_copy(stdscr); wmove(stdscr,4,0); aff_part(stdscr,AFF_PART_ORDER|AFF_PART_STATUS,disk_car,partition); screen_buffer_display(stdscr,"",menuType); wmove(stdscr,LINES-2,0); wclrtoeol(stdscr); wprintw(stdscr,"New partition type [current %02x] ? ",partition->arch->get_part_type(partition)); if (get_string(stdscr, response, sizeof(response), NULL) > 0) { int tmp_val = strtol(response, NULL, 16); partition->arch->set_part_type(partition,tmp_val); } }
list_part_t *read_part_gpt(disk_t *disk, const int verbose, const int saveheader) { list_part_t *list_part; screen_buffer_reset(); if((list_part=read_part_gpt_aux(disk, verbose, saveheader, 1))!=NULL) return list_part; screen_buffer_add( "Trying alternate GPT\n"); list_part=read_part_gpt_aux(disk, verbose, saveheader, (disk->disk_size-1)/disk->sector_size); screen_buffer_to_log(); return list_part; }
int exFAT_boot_sector(disk_t *disk, partition_t *partition, char **current_cmd) { unsigned char *buffer_bs; unsigned char *buffer_backup_bs; int rescan=1; const int size_bs=12 * disk->sector_size; const char *options; #ifdef HAVE_NCURSES const struct MenuItem menu_exFAT[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q', "Quit","Return to Advanced menu"}, { 'O', "Org. BS","Copy superblock over backup sector"}, { 'B', "Backup BS","Copy backup superblock over superblock"}, { 'D', "Dump","Dump superblock and backup superblock"}, { 0, NULL, NULL } }; #endif buffer_bs=(unsigned char*)MALLOC(size_bs); buffer_backup_bs=(unsigned char*)MALLOC(size_bs); while(1) { int command; screen_buffer_reset(); if(rescan==1) { options=exFAT_boot_sector_rescan(disk, partition, buffer_bs, buffer_backup_bs); rescan=0; } screen_buffer_to_log(); if(*current_cmd!=NULL) { command=exFAT_boot_sector_command(current_cmd, options); } else { #ifdef HAVE_NCURSES unsigned int menu=0; #endif log_flush(); #ifdef HAVE_NCURSES command=screen_buffer_display_ext(stdscr, options, menu_exFAT, &menu); #else command=0; #endif } switch(command) { case 0: free(buffer_bs); free(buffer_backup_bs); return 0; case 'O': /* O : copy original superblock over backup boot */ #ifdef HAVE_NCURSES if(ask_confirmation("Copy original exFAT boot record over backup, confirm ? (Y/N)")!=0) #endif { log_info("copy original superblock over backup boot\n"); if(disk->pwrite(disk, buffer_bs, size_bs, partition->part_offset + size_bs) != size_bs) { display_message("Write error: Can't overwrite exFAT backup boot record\n"); } disk->sync(disk); rescan=1; } break; case 'B': /* B : copy backup superblock over main superblock */ #ifdef HAVE_NCURSES if(ask_confirmation("Copy backup exFAT boot record over main boot record, confirm ? (Y/N)")!=0) #endif { log_info("copy backup superblock over main superblock\n"); /* Reset information about backup boot record */ partition->sb_offset=0; if(disk->pwrite(disk, buffer_backup_bs, size_bs, partition->part_offset) != size_bs) { display_message("Write error: Can't overwrite exFAT main boot record\n"); } disk->sync(disk); rescan=1; } break; case 'D': exFAT_dump(disk, partition, buffer_bs, buffer_backup_bs, current_cmd); break; } } }
list_part_t *read_part_gpt(disk_t *disk_car, const int verbose, const int saveheader) { struct gpt_hdr *gpt; struct gpt_ent* gpt_entries; list_part_t *new_list_part=NULL; unsigned int i; uint32_t gpt_entries_size; uint64_t gpt_entries_offset; gpt=(struct gpt_hdr*)MALLOC(disk_car->sector_size); screen_buffer_reset(); if((unsigned)disk_car->pread(disk_car, gpt, disk_car->sector_size, disk_car->sector_size) != disk_car->sector_size) { free(gpt); return NULL; } if(memcmp(gpt->hdr_sig, GPT_HDR_SIG, 8)!=0) { screen_buffer_add("Bad GPT partition, invalid signature.\n"); free(gpt); return NULL; } if(verbose>0) { log_info("hdr_size=%llu\n", (long long unsigned)le32(gpt->hdr_size)); log_info("hdr_lba_self=%llu\n", (long long unsigned)le64(gpt->hdr_lba_self)); log_info("hdr_lba_alt=%llu (expected %llu)\n", (long long unsigned)le64(gpt->hdr_lba_alt), (long long unsigned)((disk_car->disk_size-1)/disk_car->sector_size)); log_info("hdr_lba_start=%llu\n", (long long unsigned)le64(gpt->hdr_lba_start)); log_info("hdr_lba_end=%llu\n", (long long unsigned)le64(gpt->hdr_lba_end)); log_info("hdr_lba_table=%llu\n", (long long unsigned)le64(gpt->hdr_lba_table)); log_info("hdr_entries=%llu\n", (long long unsigned)le32(gpt->hdr_entries)); log_info("hdr_entsz=%llu\n", (long long unsigned)le32(gpt->hdr_entsz)); } /* Check header size */ if(le32(gpt->hdr_size)<92 || le32(gpt->hdr_size) > disk_car->sector_size) { screen_buffer_add("GPT: invalid header size.\n"); free(gpt); return NULL; } { /* CRC check */ uint32_t crc; uint32_t origcrc; origcrc=le32(gpt->hdr_crc_self); gpt->hdr_crc_self=le32(0); crc=get_crc32(gpt, le32(gpt->hdr_size), 0xFFFFFFFF)^0xFFFFFFFF; if(crc!=origcrc) { screen_buffer_add("Bad GPT partition, invalid header checksum.\n"); free(gpt); return NULL; } gpt->hdr_crc_self=le32(origcrc); } if(le64(gpt->hdr_lba_self)!=1) { screen_buffer_add("Bad GPT partition, invalid LBA self location.\n"); free(gpt); return NULL; } if(le64(gpt->hdr_lba_start) >= le64(gpt->hdr_lba_end)) { screen_buffer_add("Bad GPT partition, invalid LBA start/end location.\n"); free(gpt); return NULL; } if(le32(gpt->hdr_revision)!=GPT_HDR_REVISION) { screen_buffer_add("GPT: Warning - not revision 1.0\n"); } if(le32(gpt->__reserved)!=0) { screen_buffer_add("GPT: Warning - __reserved!=0\n"); } if(le32(gpt->hdr_entries)==0 || le32(gpt->hdr_entries)>4096) { screen_buffer_add("GPT: invalid number (%u) of partition entries.\n", (unsigned int)le32(gpt->hdr_entries)); free(gpt); return NULL; } /* le32(gpt->hdr_entsz)==128 */ if(le32(gpt->hdr_entsz)%8!=0 || le32(gpt->hdr_entsz)<128 || le32(gpt->hdr_entsz)>4096) { screen_buffer_add("GPT: invalid partition entry size.\n"); free(gpt); return NULL; } gpt_entries_size=le32(gpt->hdr_entries) * le32(gpt->hdr_entsz); if(gpt_entries_size<16384) { screen_buffer_add("GPT: A minimum of 16,384 bytes of space must be reserved for the GUID Partition Entry array.\n"); free(gpt); return NULL; } gpt_entries_offset=(uint64_t)le64(gpt->hdr_lba_table) * disk_car->sector_size; if((uint64_t) le64(gpt->hdr_lba_self) + le32(gpt->hdr_size) - 1 >= gpt_entries_offset || gpt_entries_offset >= le64(gpt->hdr_lba_start) * disk_car->sector_size) { screen_buffer_add( "GPT: The primary GUID Partition Entry array must be located after the primary GUID Partition Table Header and end before the FirstUsableLBA.\n"); free(gpt); return NULL; } gpt_entries=(struct gpt_ent*)MALLOC(gpt_entries_size); if((unsigned)disk_car->pread(disk_car, gpt_entries, gpt_entries_size, gpt_entries_offset) != gpt_entries_size) { free(gpt_entries); free(gpt); return new_list_part; } { /* CRC check */ uint32_t crc; crc=get_crc32(gpt_entries, gpt_entries_size, 0xFFFFFFFF)^0xFFFFFFFF; if(crc!=le32(gpt->hdr_crc_table)) { screen_buffer_add("Bad GPT partition entries, invalid checksum.\n"); free(gpt_entries); free(gpt); return NULL; } } for(i=0;i<le32(gpt->hdr_entries);i++) { const struct gpt_ent* gpt_entry; gpt_entry=(const struct gpt_ent*)((const char*)gpt_entries + (unsigned long)i*le32(gpt->hdr_entsz)); if(guid_cmp(gpt_entry->ent_type, GPT_ENT_TYPE_UNUSED)!=0 && le64(gpt_entry->ent_lba_start) < le64(gpt_entry->ent_lba_end)) { int insert_error=0; partition_t *new_partition=partition_new(&arch_gpt); new_partition->order=i+1; guid_cpy(&new_partition->part_uuid, &gpt_entry->ent_uuid); guid_cpy(&new_partition->part_type_gpt, &gpt_entry->ent_type); new_partition->part_offset=(uint64_t)le64(gpt_entry->ent_lba_start)*disk_car->sector_size; new_partition->part_size=(uint64_t)(le64(gpt_entry->ent_lba_end) - le64(gpt_entry->ent_lba_start)+1) * disk_car->sector_size; new_partition->status=STATUS_PRIM; UCSle2str(new_partition->partname, (const uint16_t *)&gpt_entry->ent_name, sizeof(gpt_entry->ent_name)/2); new_partition->arch->check_part(disk_car,verbose,new_partition,saveheader); /* log_debug("%u ent_attr %08llx\n", new_partition->order, (long long unsigned)le64(gpt_entry->ent_attr)); */ aff_part_buffer(AFF_PART_ORDER|AFF_PART_STATUS,disk_car,new_partition); new_list_part=insert_new_partition(new_list_part, new_partition, 0, &insert_error); if(insert_error>0) free(new_partition); } } /* TODO: The backup GUID Partition Entry array must be located after the LastUsableLBA and end before the backup GUID Partition Table Header. */ free(gpt_entries); free(gpt); return new_list_part; }
dir_partition_t dir_partition(disk_t *disk, const partition_t *partition, const int verbose, char **current_cmd) { dir_data_t dir_data; #ifdef HAVE_NCURSES WINDOW *window; #endif dir_partition_t res; fflush(stderr); dir_data.local_dir=NULL; res=dir_partition_init(disk, partition, verbose, &dir_data); #ifdef HAVE_NCURSES window=newwin(LINES, COLS, 0, 0); /* full screen */ dir_data.display=window; aff_copy(window); #else dir_data.display=NULL; #endif log_info("\n"); switch(res) { case DIR_PART_ENOSYS: screen_buffer_reset(); #ifdef HAVE_NCURSES aff_copy(window); wmove(window,4,0); aff_part(window,AFF_PART_ORDER|AFF_PART_STATUS,disk,partition); #endif log_partition(disk,partition); screen_buffer_add("Support for this filesystem hasn't been enable during compilation.\n"); screen_buffer_to_log(); if(*current_cmd==NULL) { #ifdef HAVE_NCURSES screen_buffer_display(window,"",NULL); #endif } break; case DIR_PART_EIO: screen_buffer_reset(); #ifdef HAVE_NCURSES aff_copy(window); wmove(window,4,0); aff_part(window,AFF_PART_ORDER|AFF_PART_STATUS,disk,partition); #endif log_partition(disk,partition); screen_buffer_add("Can't open filesystem. Filesystem seems damaged.\n"); screen_buffer_to_log(); if(*current_cmd==NULL) { #ifdef HAVE_NCURSES screen_buffer_display(window,"",NULL); #endif } break; case DIR_PART_OK: { int recursive=0; if(*current_cmd!=NULL) { int do_continue; do { do_continue=0; while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"recursive",9)==0) { (*current_cmd)+=9; recursive=1; do_continue=1; } else if(strncmp(*current_cmd,"fullpathname",12)==0) { (*current_cmd)+=12; dir_data.param|=FLAG_LIST_PATHNAME; do_continue=1; } } while(do_continue==1); } if(recursive>0) dir_whole_partition_log(disk,partition,&dir_data,dir_data.current_inode); else { #ifdef HAVE_NCURSES dir_partition_aff(disk, partition, &dir_data, dir_data.current_inode, current_cmd); #else { file_info_t dir_list = { .list = TD_LIST_HEAD_INIT(dir_list.list), .name = NULL }; dir_data.get_dir(disk, partition, &dir_data, dir_data.current_inode, &dir_list); dir_aff_log(&dir_data, &dir_list); delete_list_file(&dir_list); } #endif } dir_data.close(&dir_data); } break; } #ifdef HAVE_NCURSES delwin(window); (void) clearok(stdscr, TRUE); #ifdef HAVE_TOUCHWIN touchwin(stdscr); #endif wrefresh(stdscr); #endif fflush(stderr); free(dir_data.local_dir); return res; }
int main( int argc, char **argv ) { int i; int use_sudo=0; int create_log=TD_LOG_NONE; int run_setlocale=1; int testdisk_mode=TESTDISK_O_RDONLY|TESTDISK_O_READAHEAD_32K; list_disk_t *list_disk=NULL; list_disk_t *element_disk; const char *logfile="photorec.log"; FILE *log_handle=NULL; int log_errno=0; struct ph_options options={ .paranoid=1, .keep_corrupted_file=0, .mode_ext2=0, .expert=0, .lowmem=0, .verbose=0, .list_file_format=list_file_enable }; struct ph_param params; params.recup_dir=NULL; params.cmd_device=NULL; params.cmd_run=NULL; params.carve_free_space_only=0; /* random (weak is ok) is need fot GPT */ srand(time(NULL)); #ifdef HAVE_SIGACTION /* set up the signal handler for SIGINT & SIGHUP */ sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGINT); sigaddset(&action.sa_mask, SIGHUP); action.sa_handler = sighup_hdlr; action.sa_flags = 0; if(sigaction(SIGINT, &action, NULL)==-1) { printf("Error on SIGACTION call\n"); return -1; } if(sigaction(SIGHUP, &action, NULL)==-1) { printf("Error on SIGACTION call\n"); return -1; } #endif printf("PhotoRec %s, Data Recovery Utility, %s\nChristophe GRENIER <*****@*****.**>\nhttp://www.cgsecurity.org\n",VERSION,TESTDISKDATE); for(i=1;i<argc;i++) { if((strcmp(argv[i],"/logname")==0) ||(strcmp(argv[i],"-logname")==0)) { if(i+2>=argc) { display_help(); free(params.recup_dir); return 1; } logfile=argv[++i]; } else if((strcmp(argv[i],"/log")==0) ||(strcmp(argv[i],"-log")==0)) { if(create_log==TD_LOG_NONE) create_log=TD_LOG_APPEND; } else if((strcmp(argv[i],"/debug")==0) || (strcmp(argv[i],"-debug")==0)) { options.verbose++; if(create_log==TD_LOG_NONE) create_log=TD_LOG_APPEND; } else if(((strcmp(argv[i],"/d")==0)||(strcmp(argv[i],"-d")==0)) &&(i+1<argc)) { int len=strlen(argv[i+1]); if(argv[i+1][len-1]=='\\' || argv[i+1][len-1]=='/') { params.recup_dir=(char *)MALLOC(len + strlen(DEFAULT_RECUP_DIR) + 1); strcpy(params.recup_dir,argv[i+1]); strcat(params.recup_dir,DEFAULT_RECUP_DIR); } else params.recup_dir=strdup(argv[i+1]); i++; } else if((strcmp(argv[i],"/all")==0) || (strcmp(argv[i],"-all")==0)) testdisk_mode|=TESTDISK_O_ALL; else if((strcmp(argv[i],"/direct")==0) || (strcmp(argv[i],"-direct")==0)) testdisk_mode|=TESTDISK_O_DIRECT; else if((strcmp(argv[i],"/help")==0) || (strcmp(argv[i],"-help")==0) || (strcmp(argv[i],"--help")==0) || (strcmp(argv[i],"/h")==0) || (strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"/?")==0) || (strcmp(argv[i],"-?")==0)) { display_help(); free(params.recup_dir); return 0; } else if((strcmp(argv[i],"/version")==0) || (strcmp(argv[i],"-version")==0) || (strcmp(argv[i],"--version")==0) || (strcmp(argv[i],"/v")==0) || (strcmp(argv[i],"-v")==0)) { display_version(); free(params.recup_dir); return 0; } else if((strcmp(argv[i],"/nosetlocale")==0) || (strcmp(argv[i],"-nosetlocale")==0)) run_setlocale=0; else if(strcmp(argv[i],"/cmd")==0) { if(i+2>=argc) { display_help(); free(params.recup_dir); return 1; } { disk_t *disk_car; params.cmd_device=argv[++i]; params.cmd_run=argv[++i]; /* There is no log currently */ disk_car=file_test_availability(params.cmd_device, options.verbose, testdisk_mode); if(disk_car==NULL) { printf("\nUnable to open file or device %s: %s\n", params.cmd_device, strerror(errno)); free(params.recup_dir); return 1; } list_disk=insert_new_disk(list_disk,disk_car); } } else { disk_t *disk_car=file_test_availability(argv[i], options.verbose, testdisk_mode); if(disk_car==NULL) { printf("\nUnable to open file or device %s: %s\n", argv[i], strerror(errno)); free(params.recup_dir); return 1; } list_disk=insert_new_disk(list_disk,disk_car); } } #ifdef ENABLE_DFXML xml_set_command_line(argc, argv); #endif if(create_log!=TD_LOG_NONE) log_handle=log_open(logfile, create_log, &log_errno); #ifdef HAVE_SETLOCALE if(run_setlocale>0) { const char *locale; locale = setlocale (LC_ALL, ""); if (locale==NULL) { locale = setlocale (LC_ALL, NULL); log_error("Failed to set locale, using default '%s'.\n", locale); } else { log_info("Using locale '%s'.\n", locale); } } #endif if(create_log!=TD_LOG_NONE && log_handle==NULL) log_handle=log_open_default(logfile, create_log, &log_errno); #ifdef HAVE_NCURSES /* ncurses need locale for correct unicode support */ if(start_ncurses("PhotoRec", argv[0])) { free(params.recup_dir); return 1; } { const char*filename=logfile; while(create_log!=TD_LOG_NONE && log_handle==NULL) { filename=ask_log_location(filename, log_errno); if(filename!=NULL) log_handle=log_open(filename, create_log, &log_errno); else create_log=TD_LOG_NONE; } } aff_copy(stdscr); wmove(stdscr,5,0); wprintw(stdscr, "Disk identification, please wait...\n"); wrefresh(stdscr); #endif if(log_handle!=NULL) { time_t my_time; #ifdef HAVE_DUP2 dup2(fileno(log_handle),2); #endif my_time=time(NULL); log_info("\n\n%s",ctime(&my_time)); log_info("Command line: PhotoRec"); for(i=1;i<argc;i++) log_info(" %s", argv[i]); log_info("\n\n"); } log_info("PhotoRec %s, Data Recovery Utility, %s\nChristophe GRENIER <*****@*****.**>\nhttp://www.cgsecurity.org\n", VERSION, TESTDISKDATE); log_info("OS: %s\n" , get_os()); log_info("Compiler: %s\n", get_compiler()); log_info("Compilation date: %s\n", get_compilation_date()); log_info("ext2fs lib: %s, ntfs lib: %s, ewf lib: %s, libjpeg: %s\n", td_ext2fs_version(), td_ntfs_version(), td_ewf_version(), td_jpeg_version()); #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) #else #ifdef HAVE_GETEUID if(geteuid()!=0) { log_warning("User is not root!\n"); } #endif #endif log_flush(); screen_buffer_reset(); /* Scan for available device only if no device or image has been supplied in parameter */ if(list_disk==NULL) list_disk=hd_parse(list_disk, options.verbose, testdisk_mode); hd_update_all_geometry(list_disk, options.verbose); /* Activate the cache, even if photorec has its own */ for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) { element_disk->disk=new_diskcache(element_disk->disk, testdisk_mode); } log_disk_list(list_disk); reset_list_file_enable(options.list_file_format); file_options_load(options.list_file_format); #ifdef SUDO_BIN if(list_disk==NULL) { #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) #else #ifdef HAVE_GETEUID if(geteuid()!=0) use_sudo=2; #endif #endif } #endif if(use_sudo==0) use_sudo=do_curses_photorec(¶ms, &options, list_disk); #ifdef HAVE_NCURSES end_ncurses(); #endif log_info("PhotoRec exited normally.\n"); if(log_close()!=0) { printf("PhotoRec: Log file corrupted!\n"); } else if(params.cmd_run!=NULL && params.cmd_run[0]!='\0') { printf("PhotoRec syntax error: %s\n", params.cmd_run); } #ifdef SUDO_BIN if(use_sudo>0) { printf("\n"); if(use_sudo>1) printf("No disk found.\n"); printf("PhotoRec will try to restart itself using the sudo command to get\n"); printf("root (superuser) privileges.\n"); printf("\n"); run_sudo(argc, argv); } #endif delete_list_disk(list_disk); free(params.recup_dir); #ifdef ENABLE_DFXML xml_clear_command_line(); #endif return 0; }
static list_part_t *read_part_none(disk_t *disk, const int verbose, const int saveheader) { int insert_error=0; unsigned char *buffer_disk; list_part_t *list_part; partition_t *partition; int res=0; partition=partition_new(&arch_none); buffer_disk=(unsigned char *)MALLOC(16*DEFAULT_SECTOR_SIZE); partition->part_size=disk->disk_size; if(recover_MD_from_partition(disk, partition, verbose)==0) res=1; else partition_reset(partition,&arch_none); if(res<=0) { if(disk->pread(disk, buffer_disk, 16 * DEFAULT_SECTOR_SIZE, partition->part_offset) == 16 * DEFAULT_SECTOR_SIZE) res=search_type_2(buffer_disk, disk, partition,verbose,0); } if(res<=0) { res=search_type_1(buffer_disk, disk, partition,verbose,0); } if(res<=0) { res=search_type_0(buffer_disk, disk, partition,verbose,0); } if(res<=0) { res=search_type_8(buffer_disk, disk, partition,verbose,0); } if(res<=0) { if(disk->pread(disk, buffer_disk, 3 * DEFAULT_SECTOR_SIZE, partition->part_offset + 16 * 512) == 3 * DEFAULT_SECTOR_SIZE) res=search_type_16(buffer_disk, disk, partition,verbose,0); } if(res<=0) { if(disk->pread(disk, buffer_disk, 3 * DEFAULT_SECTOR_SIZE, partition->part_offset + 63 * 512) == 3 * DEFAULT_SECTOR_SIZE) res=search_type_64(buffer_disk, disk, partition,verbose,0); } if(res<=0) res=(recover_ISO((const struct iso_primary_descriptor*)(buffer_disk+0x200), partition)==0); if(res<=0) { /* 64k offset */ if(disk->pread(disk, buffer_disk, 11 * DEFAULT_SECTOR_SIZE, partition->part_offset + 126 * 512) == 11 * DEFAULT_SECTOR_SIZE) res=search_type_128(buffer_disk, disk, partition,verbose,0); } if(res<=0) { res=search_type_2048(buffer_disk, disk, partition,verbose,0); } if(res<=0) { /* Search FAT32 backup */ partition->part_offset = 6*512; res=search_FAT_backup(buffer_disk, disk, partition, verbose, 0); } if(res<=0) { /* Search exFAT backup */ partition->part_offset = 12 * disk->sector_size; res=search_EXFAT_backup(buffer_disk, disk, partition); } if(res<=0) { /* Search NTFS backup */ if(disk->disk_size > disk->sector_size) { partition->part_offset = disk->disk_size - disk->sector_size; res=search_NTFS_backup(buffer_disk, disk, partition, verbose, 0); if(res>0 && partition->part_offset!=0) res=0; } } if(res<=0) { int s_log_block_size; for(s_log_block_size=0; s_log_block_size<=2 && res<=0; s_log_block_size++) { /* sparse superblock feature: The groups chosen are 0, 1 and powers of 3, 5 and 7. */ /* Checking group 3 */ const uint64_t hd_offset=3*(EXT2_MIN_BLOCK_SIZE<<s_log_block_size)*8*(EXT2_MIN_BLOCK_SIZE<<s_log_block_size)+(s_log_block_size==0?2*DEFAULT_SECTOR_SIZE:0); if(disk->pread(disk, buffer_disk, 1024, hd_offset)==1024) { const struct ext2_super_block *sb=(const struct ext2_super_block*)buffer_disk; partition->part_offset = hd_offset; if(le16(sb->s_block_group_nr)>0 && le16(sb->s_magic)==EXT2_SUPER_MAGIC && recover_EXT2(disk, sb, partition, 0, 0)==0) res=1; if(res>0 && partition->part_offset!=0) res=0; } } } free(buffer_disk); if(res<=0) partition_reset(partition,&arch_none); partition->part_offset=0; partition->part_size=disk->disk_size; partition->order=NO_ORDER; partition->status=STATUS_PRIM; screen_buffer_reset(); disk->arch->check_part(disk, verbose,partition,saveheader); aff_part_buffer(AFF_PART_ORDER|AFF_PART_STATUS,disk, partition); list_part=insert_new_partition(NULL, partition, 0, &insert_error); if(insert_error>0) free(partition); return list_part; }
static list_part_t *interface_analyse_ncurses(disk_t *disk_car, const int verbose, const int saveheader, char**current_cmd) { list_part_t *list_part; int command; #ifdef HAVE_NCURSES const struct MenuItem menuAnalyse[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q',"Quick Search","Try to locate partition"}, { 'B', "Backup","Save current partition list to backup.log file and proceed"}, { 0, NULL, NULL } }; #endif screen_buffer_reset(); /* ncurses interface */ #ifdef HAVE_NCURSES aff_copy(stdscr); wmove(stdscr,4,0); wprintw(stdscr,"%s\n",disk_car->description(disk_car)); mvwaddstr(stdscr,5,0,"Checking current partition structure"); wrefresh(stdscr); #endif list_part=disk_car->arch->read_part(disk_car,verbose,saveheader); log_info("Current partition structure:\n"); screen_buffer_to_log(); #ifdef HAVE_NCURSES wmove(stdscr,5,0); wclrtoeol(stdscr); /* before addstr for BSD compatibility */ waddstr(stdscr,"Current partition structure:"); wmove(stdscr,6,0); wprintw(stdscr,msg_PART_HEADER_LONG); if(disk_car->arch->msg_part_type!=NULL) mvwaddstr(stdscr,LINES-3,0,disk_car->arch->msg_part_type); #endif command='Q'; if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"backup",6)==0) { (*current_cmd)+=6; if(list_part!=NULL) command='B'; } } else { log_flush(); #ifdef HAVE_NCURSES command=screen_buffer_display(stdscr, (list_part!=NULL && disk_car->arch != &arch_none?"QB":"Q"), menuAnalyse); #endif } if(command=='B') { log_info("Backup partition structure\n"); if(partition_save(disk_car,list_part,verbose)<0) { display_message("Can't create backup.log.\n"); } } return list_part; }
static list_part_t *search_part(disk_t *disk_car, const list_part_t *list_part_org, const int verbose, const int dump_ind, const int fast_mode, char **current_cmd) { unsigned char *buffer_disk; unsigned char *buffer_disk0; /* TODO use circular buffer for try_offset and try_offset_raid */ uint64_t try_offset[MAX_SEARCH_LOCATION]; uint64_t try_offset_raid[MAX_SEARCH_LOCATION]; const uint64_t min_location=get_min_location(disk_car); uint64_t search_location; unsigned int try_offset_nbr=0; unsigned int try_offset_raid_nbr=0; #ifdef HAVE_NCURSES unsigned int old_cylinder=0; #endif const unsigned int location_boundary=get_location_boundary(disk_car); indstop_t ind_stop=INDSTOP_CONTINUE; list_part_t *list_part=NULL; list_part_t *list_part_bad=NULL; partition_t *partition; /* It's not a problem to read a little bit more than necessary */ const uint64_t search_location_max=td_max((disk_car->disk_size / ((uint64_t) disk_car->geom.heads_per_cylinder * disk_car->geom.sectors_per_head * disk_car->sector_size) + 1 ) * ((uint64_t) disk_car->geom.heads_per_cylinder * disk_car->geom.sectors_per_head * disk_car->sector_size), disk_car->disk_real_size); assert(disk_car->sector_size>0); partition=partition_new(disk_car->arch); buffer_disk=(unsigned char*)MALLOC(16*DEFAULT_SECTOR_SIZE); buffer_disk0=(unsigned char*)MALLOC(16*DEFAULT_SECTOR_SIZE); { /* Will search for partition at current known partition location */ const list_part_t *element; for(element=list_part_org;element!=NULL;element=element->next) { hint_insert(try_offset, element->part->part_offset, &try_offset_nbr); } } #ifdef HAVE_NCURSES wmove(stdscr,22,0); wattrset(stdscr, A_REVERSE); waddstr(stdscr," Stop "); wattroff(stdscr, A_REVERSE); #endif screen_buffer_reset(); log_info("\nsearch_part()\n"); log_info("%s\n",disk_car->description(disk_car)); search_location=min_location; search_add_hints(disk_car, try_offset, &try_offset_nbr); /* Not every sector will be examined */ search_location_init(disk_car, location_boundary, fast_mode); /* Scan the disk */ while(ind_stop!=INDSTOP_QUIT && search_location < search_location_max) { CHS_t start; offset2CHS_inline(disk_car,search_location,&start); #ifdef HAVE_NCURSES if(disk_car->geom.heads_per_cylinder>1) { if(old_cylinder!=start.cylinder) { old_cylinder=start.cylinder; wmove(stdscr,ANALYSE_Y,ANALYSE_X); wclrtoeol(stdscr); wprintw(stdscr,"Analyse cylinder %5u/%u: %02u%%", start.cylinder, disk_car->geom.cylinders-1, (unsigned int)(search_location*100/disk_car->disk_size)); wrefresh(stdscr); switch(check_enter_key_or_s(stdscr)) { case 1: ind_stop=INDSTOP_STOP; break; case 2: ind_stop=INDSTOP_SKIP; break; } } } else if((start.cylinder & 0x7FFF)==0) { wmove(stdscr,ANALYSE_Y,ANALYSE_X); wclrtoeol(stdscr); wprintw(stdscr,"Analyse sector %11llu/%lu: %02u%%", search_location / disk_car->sector_size, (disk_car->disk_size-1)/disk_car->sector_size, (unsigned int)(search_location*100/disk_car->disk_size)); wrefresh(stdscr); switch(check_enter_key_or_s(stdscr)) { case 1: ind_stop=INDSTOP_STOP; break; case 2: ind_stop=INDSTOP_SKIP; break; } } #endif { unsigned int sector_inc=0; int test_nbr=0; int search_now=0; int search_now_raid=0; while(try_offset_nbr>0 && try_offset[0]<=search_location) { unsigned int j; if(try_offset[0]==search_location) search_now=1; for(j=0;j<try_offset_nbr-1;j++) try_offset[j]=try_offset[j+1]; try_offset_nbr--; } /* PC x/0/1 x/1/1 x/2/1 */ /* PC Vista 2048 sectors unit */ if(disk_car->arch==&arch_i386) search_now|= (start.sector==1 && fast_mode>1) || (start.sector==1 && start.head<=2) || search_location%(2048*512)==0; else search_now|= (search_location%location_boundary==0); while(try_offset_raid_nbr>0 && try_offset_raid[0]<=search_location) { unsigned int j; if(try_offset_raid[0]==search_location) search_now_raid=1; for(j=0;j<try_offset_raid_nbr-1;j++) try_offset_raid[j]=try_offset_raid[j+1]; try_offset_raid_nbr--; } do { int res=0; partition->part_size=(uint64_t)0; partition->part_offset=search_location; if(res<=0 && test_nbr==0) { if(search_now_raid>0 || fast_mode>1) { /* Search Linux software RAID */ if(disk_car->pread(disk_car, buffer_disk, 8 * DEFAULT_SECTOR_SIZE, search_location) == 8 *DEFAULT_SECTOR_SIZE) { if(recover_MD(disk_car, (const struct mdp_superblock_s*)buffer_disk, partition, verbose, dump_ind)==0) { const struct mdp_superblock_1 *sb1=(const struct mdp_superblock_1 *)buffer_disk; if(le32(sb1->md_magic)==(unsigned int)MD_SB_MAGIC) { if(le32(sb1->major_version)==0) partition->part_offset-=(uint64_t)MD_NEW_SIZE_SECTORS(partition->part_size/512)*512; else partition->part_offset-=le64(sb1->super_offset)*512; } else { if(be32(sb1->major_version)==0) partition->part_offset-=(uint64_t)MD_NEW_SIZE_SECTORS(partition->part_size/512)*512; else partition->part_offset-=be64(sb1->super_offset)*512; } res=1; } else res=0; } } test_nbr++; } if(res<=0 && test_nbr==1) { if((disk_car->arch==&arch_i386 && ((start.sector==7 && (start.head<=2 || fast_mode>1)) || search_location%(2048*512)==(7-1)*512)) || (disk_car->arch!=&arch_i386 && (search_location%location_boundary==(7-1)*512)) || (disk_car->arch==&arch_gpt&& (search_location%(2048*512)==(7-1)*512)) || (disk_car->arch==&arch_none && search_location==(7-1)*512)) res=search_FAT_backup(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==2) { if((disk_car->arch==&arch_i386 && ((start.sector==13 && (start.head<=2 || fast_mode>1)) || search_location%(2048*512)==(13-1)*disk_car->sector_size)) || (disk_car->arch==&arch_gpt&& (search_location%(2048*512)==(13-1)*512)) || (disk_car->arch!=&arch_i386 && (search_location%location_boundary==(13-1)*disk_car->sector_size))) res=search_EXFAT_backup(buffer_disk, disk_car, partition); test_nbr++; } if(res<=0 && test_nbr==3) { if((disk_car->arch==&arch_i386 && ((start.sector==disk_car->geom.sectors_per_head && (start.head==disk_car->geom.heads_per_cylinder-1 || fast_mode>1)) || search_location%(2048*512)==(2048-1)*512)) || (disk_car->arch==&arch_gpt&& (search_location%(2048*512)==(2048-1)*512)) || (disk_car->arch!=&arch_i386 && search_location%location_boundary==(location_boundary-512) && search_location>0)) res=search_NTFS_backup(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==4) { if((disk_car->arch==&arch_i386 && ((start.sector==disk_car->geom.sectors_per_head && (start.head==disk_car->geom.heads_per_cylinder-1 || fast_mode>1)) || search_location%(2048*512)==(2048-1)*512)) || (disk_car->arch!=&arch_i386 && search_location%location_boundary==(location_boundary-512) && search_location>0)) res=search_HFS_backup(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==5) { int s_log_block_size; /* try backup superblock */ /* It must be in fast_mode>0 because it can hide otherwise other partition type */ /* Block size: 1024, 2048 or 4096 bytes (8192 bytes on Alpha systems) */ /* From e2fsprogs-1.34/lib/ext2fs/initialize.c: set_field(s_first_data_block, super->s_log_block_size ? 0 : 1); */ /* Assumes that TestDisk is not running under Alpha and s_blocks_per_group=8 * block size */ for(s_log_block_size=0;(s_log_block_size<=2)&&(res<=0);s_log_block_size++) { /* sparse superblock feature: The groups chosen are 0, 1 and powers of 3, 5 and 7. */ /* Checking group 3 */ const uint64_t hd_offset=3*(EXT2_MIN_BLOCK_SIZE<<s_log_block_size)*8*(EXT2_MIN_BLOCK_SIZE<<s_log_block_size)+(s_log_block_size==0?2*DEFAULT_SECTOR_SIZE:0); if(search_location>=hd_offset) { CHS_t start_ext2; offset2CHS_inline(disk_car,search_location-hd_offset,&start_ext2); if((disk_car->arch==&arch_i386 && start_ext2.sector==1 && (start_ext2.head<=2 || fast_mode>1)) || (disk_car->arch==&arch_i386 && (search_location-hd_offset)%(2048*512)==0) || (disk_car->arch!=&arch_i386 && (search_location-hd_offset)%location_boundary==0)) { if(disk_car->pread(disk_car, buffer_disk, 1024, search_location)==1024) { const struct ext2_super_block *sb=(const struct ext2_super_block*)buffer_disk; if(le16(sb->s_magic)==EXT2_SUPER_MAGIC && le16(sb->s_block_group_nr)>0 && recover_EXT2(disk_car, sb, partition, verbose, dump_ind)==0) res=1; } } } } test_nbr++; } if(res<=0 && test_nbr==6) { if(search_now==0) test_nbr=14; else { if(disk_car->pread(disk_car, buffer_disk0, 16 * DEFAULT_SECTOR_SIZE, partition->part_offset) == 16 * DEFAULT_SECTOR_SIZE) res=search_type_2(buffer_disk0,disk_car,partition,verbose,dump_ind); else res=-1; test_nbr++; } } if(res<=0 && test_nbr==7) { if(res==0) res=search_type_1(buffer_disk0, disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==8) { if(res==0) res=search_type_0(buffer_disk0,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==9) { res=search_type_8(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==10) { /* Try to catch disklabel before BSD FFS partition */ res=search_type_16(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==11) { res=search_type_64(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==12) { /* read to fill the cache */ disk_car->pread(disk_car, buffer_disk, 8 * DEFAULT_SECTOR_SIZE, partition->part_offset + (63 + 16) * 512); /* Try to catch disklabel before BSD FFS partition */ res=search_type_128(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(res<=0 && test_nbr==13) { res=search_type_2048(buffer_disk,disk_car,partition,verbose,dump_ind); test_nbr++; } if(test_nbr>=14) { sector_inc=1; test_nbr=0; } if(res<0) { #ifdef HAVE_NCURSES wmove(stdscr,ANALYSE_Y+1,ANALYSE_X); wclrtoeol(stdscr); wprintw(stdscr,msg_READ_ERROR_AT, start.cylinder,start.head,start.sector,(unsigned long)(partition->part_offset/disk_car->sector_size)); #endif /* Stop reading after the end of the disk */ if(search_location >= disk_car->disk_real_size) search_location = search_location_max; } else if(res>0) { partition->status=STATUS_DELETED; log_partition(disk_car,partition); aff_part_buffer(AFF_PART_BASE, disk_car,partition); #ifdef HAVE_NCURSES screen_buffer_to_interface(); #endif if(disk_car->arch->is_part_known(partition)!=0 && partition->part_size>1 && partition->part_offset>=min_location) { const uint64_t pos_fin=partition->part_offset+partition->part_size-1; if(partition->upart_type!=UP_MD && partition->upart_type!=UP_MD1 && ind_stop==INDSTOP_CONTINUE) { /* Detect Linux md 0.9 software raid */ unsigned int disk_factor; for(disk_factor=6; disk_factor>=1;disk_factor--) { /* disk_factor=1, detect Raid 0/1 */ /* disk_factor>1, detect Raid 5 */ unsigned int help_factor; for(help_factor=0; help_factor<=MD_MAX_CHUNK_SIZE/MD_RESERVED_BYTES+3; help_factor++) { const uint64_t offset=(uint64_t)MD_NEW_SIZE_SECTORS((partition->part_size/disk_factor+help_factor*MD_RESERVED_BYTES-1)/MD_RESERVED_BYTES*MD_RESERVED_BYTES/512)*512; hint_insert(try_offset_raid, partition->part_offset+offset, &try_offset_raid_nbr); } } /* TODO: Detect Linux md 1.0 software raid */ } /* */ if(pos_fin <= search_location_max) { { int insert_error=0; partition_t *new_partition=partition_new(NULL); dup_partition_t(new_partition,partition); list_part=insert_new_partition(list_part, new_partition, 0, &insert_error); if(insert_error>0) free(new_partition); } { const uint64_t next_part_offset=partition->part_offset+partition->part_size-1+1; const uint64_t head_size=disk_car->geom.sectors_per_head * disk_car->sector_size; hint_insert(try_offset, next_part_offset, &try_offset_nbr); hint_insert(try_offset, next_part_offset+head_size, &try_offset_nbr); if(next_part_offset%head_size!=0) { hint_insert(try_offset, (next_part_offset+head_size-1)/head_size*head_size, &try_offset_nbr); hint_insert(try_offset, (next_part_offset+head_size-1)/head_size*head_size+head_size, &try_offset_nbr); } } if((fast_mode==0) && (partition->part_offset+partition->part_size-disk_car->sector_size > search_location)) { search_location=partition->part_offset+partition->part_size-disk_car->sector_size; test_nbr=0; sector_inc=1; } } else { { int insert_error=0; partition_t *new_partition=partition_new(NULL); dup_partition_t(new_partition,partition); list_part_bad=insert_new_partition(list_part_bad, new_partition, 0, &insert_error); if(insert_error>0) free(new_partition); } if(verbose>0) log_warning("This partition ends after the disk limits. (start=%llu, size=%llu, end=%llu, disk end=%llu)\n", (unsigned long long)(partition->part_offset/disk_car->sector_size), (unsigned long long)(partition->part_size/disk_car->sector_size), (unsigned long long)(pos_fin/disk_car->sector_size), (unsigned long long)(disk_car->disk_size/disk_car->sector_size)); else log_warning("This partition ends after the disk limits.\n"); } } else { if(verbose>0) { log_warning("Partition not added.\n"); } } partition_reset(partition, disk_car->arch); } } while(sector_inc==0); } if(ind_stop==INDSTOP_SKIP) { ind_stop=INDSTOP_CONTINUE; if(try_offset_nbr>0 && search_location < try_offset[0]) search_location=try_offset[0]; } else if(ind_stop==INDSTOP_STOP) { if(try_offset_nbr>0 && search_location < try_offset[0]) search_location=try_offset[0]; else ind_stop=INDSTOP_QUIT; } else { /* Optimized "search_location+=disk_car->sector_size;" */ uint64_t min=search_location_update(search_location); if(try_offset_nbr>0 && min>try_offset[0]) min=try_offset[0]; if(try_offset_raid_nbr>0 && min>try_offset_raid[0]) min=try_offset_raid[0]; if(min==(uint64_t)-1 || min<=search_location) search_location+=disk_car->sector_size; else search_location=min; } } /* Search for NTFS partition near the supposed partition beginning given by the NTFS backup boot sector */ if(fast_mode>0) search_NTFS_from_backup(disk_car, list_part, verbose, dump_ind, min_location, search_location_max); free(partition); if(ind_stop!=INDSTOP_CONTINUE) log_info("Search for partition aborted\n"); if(list_part_bad!=NULL) { interface_part_bad_log(disk_car,list_part_bad); #ifdef HAVE_NCURSES if(*current_cmd==NULL) interface_part_bad_ncurses(disk_car,list_part_bad); #endif } part_free_list(list_part_bad); free(buffer_disk0); free(buffer_disk); return list_part; }
int main( int argc, char **argv ) { int i; int use_sudo=0; int help=0, version=0, verbose=0, dump_ind=0; int create_log=TD_LOG_NONE; int do_list=0; int unit=UNIT_DEFAULT; int write_used; int saveheader=0; int create_backup=0; int run_setlocale=1; int done=0; int safe=0; int testdisk_mode=TESTDISK_O_RDWR|TESTDISK_O_READAHEAD_8K; list_disk_t *list_disk=NULL; list_disk_t *element_disk; const char *cmd_device=NULL; char *cmd_run=NULL; const char *logfile="testdisk.log"; FILE *log_handle=NULL; int log_errno=0; /* srand needed for GPT creation (weak is ok) */ srand(time(NULL)); #ifdef HAVE_SIGACTION /* set up the signal handler for SIGINT & SIGHUP */ sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, SIGINT); sigaddset(&action.sa_mask, SIGHUP); action.sa_handler = sighup_hdlr; action.sa_flags = 0; if(sigaction(SIGINT, &action, NULL)==-1) { printf("Error on SIGACTION call\n"); return -1; } if(sigaction(SIGHUP, &action, NULL)==-1) { printf("Error on SIGACTION call\n"); return -1; } #endif printf("TestDisk %s, Data Recovery Utility, %s\nChristophe GRENIER <*****@*****.**>\nhttp://www.cgsecurity.org\n",VERSION,TESTDISKDATE); for(i=1;i<argc;i++) { if((strcmp(argv[i],"/dump")==0) || (strcmp(argv[i],"-dump")==0)) dump_ind=1; else if((strcmp(argv[i],"/logname")==0) ||(strcmp(argv[i],"-logname")==0)) { if(i+2>=argc) help=1; else logfile=argv[++i]; } else if((strcmp(argv[i],"/log")==0) ||(strcmp(argv[i],"-log")==0)) { if(create_log==TD_LOG_NONE) create_log=TD_LOG_APPEND; if(log_handle==NULL) log_handle=log_open(logfile, create_log, &log_errno); } else if((strcmp(argv[i],"/debug")==0) || (strcmp(argv[i],"-debug")==0)) { verbose++; if(create_log==TD_LOG_NONE) create_log=TD_LOG_APPEND; if(log_handle==NULL) log_handle=log_open(logfile, create_log, &log_errno); } else if((strcmp(argv[i],"/all")==0) || (strcmp(argv[i],"-all")==0)) testdisk_mode|=TESTDISK_O_ALL; else if((strcmp(argv[i],"/backup")==0) || (strcmp(argv[i],"-backup")==0)) create_backup=1; else if((strcmp(argv[i],"/direct")==0) || (strcmp(argv[i],"-direct")==0)) testdisk_mode|=TESTDISK_O_DIRECT; else if((strcmp(argv[i],"/help")==0) || (strcmp(argv[i],"-help")==0) || (strcmp(argv[i],"--help")==0) || (strcmp(argv[i],"/h")==0) || (strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"/?")==0) || (strcmp(argv[i],"-?")==0)) help=1; else if((strcmp(argv[i],"/version")==0) || (strcmp(argv[i],"-version")==0) || (strcmp(argv[i],"--version")==0) || (strcmp(argv[i],"/v")==0) || (strcmp(argv[i],"-v")==0)) version=1; else if(strcmp(argv[i],"/list")==0 || strcmp(argv[i],"-list")==0 || strcmp(argv[i],"-l")==0) { do_list=1; } else if(strcmp(argv[i],"-lu")==0) { do_list=1; unit=UNIT_SECTOR; } else if((strcmp(argv[i],"/nosetlocale")==0) || (strcmp(argv[i],"-nosetlocale")==0)) run_setlocale=0; else if((strcmp(argv[i],"/safe")==0) || (strcmp(argv[i],"-safe")==0)) safe=1; else if((strcmp(argv[i],"/saveheader")==0) || (strcmp(argv[i],"-saveheader")==0)) saveheader=1; else if(strcmp(argv[i],"/cmd")==0) { if(i+2>=argc) help=1; else { disk_t *disk_car; cmd_device=argv[++i]; cmd_run=argv[++i]; disk_car=file_test_availability(cmd_device, verbose, testdisk_mode); if(disk_car==NULL) { printf("\nUnable to open file or device %s\n",cmd_device); help=1; } else list_disk=insert_new_disk(list_disk,disk_car); } } else { disk_t *disk_car=file_test_availability(argv[i], verbose, testdisk_mode); if(disk_car==NULL) { printf("\nUnable to open file or device %s\n",argv[i]); help=1; } else list_disk=insert_new_disk(list_disk,disk_car); } } if(version!=0) { printf("\n"); printf("Version: %s\n", VERSION); printf("Compiler: %s\n", get_compiler()); printf("Compilation date: %s\n", get_compilation_date()); printf("ext2fs lib: %s, ntfs lib: %s, reiserfs lib: %s, ewf lib: %s\n", td_ext2fs_version(), td_ntfs_version(), td_reiserfs_version(), td_ewf_version()); printf("OS: %s\n" , get_os()); return 0; } if(help!=0) { printf("\n" \ "Usage: testdisk [/log] [/debug] [file.dd|file.e01|device]\n"\ " testdisk /list [/log] [file.dd|file.e01|device]\n" \ " testdisk /version\n" \ "\n" \ "/log : create a testdisk.log file\n" \ "/debug : add debug information\n" \ "/list : display current partitions\n" \ "\n" \ "TestDisk checks and recovers lost partitions\n" \ "It works with :\n" \ "- BeFS (BeOS) - BSD disklabel (Free/Open/Net BSD)\n" \ "- CramFS, Compressed File System - DOS/Windows FAT12, FAT16 and FAT32\n" \ "- XBox FATX - Windows exFAT\n" \ "- HFS, HFS+, Hierarchical File System - JFS, IBM's Journaled File System\n" \ "- Linux btrfs - Linux ext2, ext3 and ext4\n" \ "- Linux GFS2 - Linux LUKS\n" \ "- Linux Raid - Linux Swap\n" \ "- LVM, LVM2, Logical Volume Manager - Netware NSS\n" \ "- Windows NTFS - ReiserFS 3.5, 3.6 and 4\n" \ "- Sun Solaris i386 disklabel - UFS and UFS2 (Sun/BSD/...)\n" \ "- XFS, SGI's Journaled File System - Wii WBFS\n" \ "- Sun ZFS\n" \ "\n" \ "If you have problems with TestDisk or bug reports, please contact me.\n"); return 0; } screen_buffer_reset(); if(do_list!=0) { printf("Please wait...\n"); /* Scan for available device only if no device or image has been supplied in parameter */ if(list_disk==NULL) list_disk=hd_parse(list_disk, verbose, testdisk_mode); /* Activate the cache */ for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) element_disk->disk=new_diskcache(element_disk->disk,testdisk_mode); if(safe==0) hd_update_all_geometry(list_disk, verbose); for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) { disk_t *disk=element_disk->disk; const int hpa_dco=is_hpa_or_dco(disk); printf("%s\n", disk->description(disk)); printf("Sector size:%u\n", disk->sector_size); if(disk->model!=NULL) printf("Model: %s", disk->model); if(disk->serial_no!=NULL) printf(", S/N:%s", disk->serial_no); if(disk->fw_rev!=NULL) printf(", FW:%s", disk->fw_rev); printf("\n"); if(hpa_dco!=0) { if(disk->sector_size!=0) printf("size %llu sectors\n", (long long unsigned)(disk->disk_real_size/disk->sector_size)); if(disk->user_max!=0) printf("user_max %llu sectors\n", (long long unsigned)disk->user_max); if(disk->native_max!=0) printf("native_max %llu sectors\n", (long long unsigned)(disk->native_max+1)); if(disk->dco!=0) printf("dco %llu sectors\n", (long long unsigned)(disk->dco+1)); if(hpa_dco&1) printf("Host Protected Area (HPA) present.\n"); if(hpa_dco&2) printf("Device Configuration Overlay (DCO) present.\n"); } printf("\n"); } for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) { disk_t *disk=element_disk->disk; autodetect_arch(disk, NULL); if(unit==UNIT_DEFAULT) autoset_unit(disk); else disk->unit=unit; interface_list(disk, verbose, saveheader, create_backup); printf("\n"); } delete_list_disk(list_disk); return 0; } #ifdef HAVE_SETLOCALE if(run_setlocale>0) { const char *locale; locale = setlocale (LC_ALL, ""); if (locale==NULL) { locale = setlocale (LC_ALL, NULL); log_error("Failed to set locale, using default '%s'.\n", locale); } else { log_info("Using locale '%s'.\n", locale); } } #endif if(create_log!=TD_LOG_NONE && log_handle==NULL) log_handle=log_open_default(logfile, create_log, &log_errno); #ifdef HAVE_NCURSES /* ncurses need locale for correct unicode support */ if(start_ncurses("TestDisk",argv[0])) return 1; if(argc==1 && create_log==TD_LOG_NONE) { verbose=1; create_log=ask_testdisk_log_creation(); if(create_log==TD_LOG_CREATE || create_log==TD_LOG_APPEND) log_handle=log_open(logfile, create_log, &log_errno); } { const char*filename=logfile; while(create_log!=TD_LOG_NONE && log_handle==NULL) { filename=ask_log_location(filename, log_errno); if(filename!=NULL) log_handle=log_open(filename, create_log, &log_errno); else create_log=TD_LOG_NONE; } } #endif if(log_handle!=NULL) { time_t my_time; #ifdef HAVE_DUP2 dup2(fileno(log_handle),2); #endif my_time=time(NULL); log_info("\n\n%s",ctime(&my_time)); log_info("Command line: TestDisk"); for(i=1;i<argc;i++) log_info(" %s", argv[i]); log_info("\n\n"); log_flush(); } log_info("TestDisk %s, Data Recovery Utility, %s\nChristophe GRENIER <*****@*****.**>\nhttp://www.cgsecurity.org\n", VERSION, TESTDISKDATE); log_info("OS: %s\n" , get_os()); log_info("Compiler: %s\n", get_compiler()); log_info("Compilation date: %s\n", get_compilation_date()); log_info("ext2fs lib: %s, ntfs lib: %s, reiserfs lib: %s, ewf lib: %s\n", td_ext2fs_version(), td_ntfs_version(), td_reiserfs_version(), td_ewf_version()); #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) #else #ifdef HAVE_GETEUID if(geteuid()!=0) { log_warning("User is not root!\n"); } #endif #endif #ifdef HAVE_NCURSES aff_copy(stdscr); wmove(stdscr,5,0); wprintw(stdscr, "Please wait...\n"); wrefresh(stdscr); #endif /* Scan for available device only if no device or image has been supplied in parameter */ if(list_disk==NULL) list_disk=hd_parse(list_disk, verbose, testdisk_mode); /* Activate the cache */ for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) element_disk->disk=new_diskcache(element_disk->disk,testdisk_mode); #ifdef HAVE_NCURSES wmove(stdscr,6,0); for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) { wprintw(stdscr,"%s\n",element_disk->disk->description(element_disk->disk)); } wrefresh(stdscr); #endif if(safe==0) hd_update_all_geometry(list_disk, verbose); /* save disk parameters to rapport */ log_info("Hard disk list\n"); for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) { disk_t *disk=element_disk->disk; log_info("%s, sector size=%u", disk->description(disk), disk->sector_size); if(disk->model!=NULL) log_info(" - %s", disk->model); if(disk->serial_no!=NULL) log_info(", S/N:%s", disk->serial_no); if(disk->fw_rev!=NULL) log_info(", FW:%s", disk->fw_rev); log_info("\n"); } log_info("\n"); #ifdef SUDO_BIN if(list_disk==NULL) { #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(DJGPP) #else #ifdef HAVE_GETEUID if(geteuid()!=0) use_sudo=2; #endif #endif } #endif if(use_sudo==0) use_sudo=do_curses_testdisk(verbose,dump_ind,list_disk,saveheader,cmd_device,&cmd_run); #ifdef HAVE_NCURSES end_ncurses(); #endif log_info("\n"); while(done==0) { int command='Q'; if(cmd_run!=NULL) { while(cmd_run[0]==',') (cmd_run)++; if(strncmp(cmd_run,"list",4)==0) { (cmd_run)+=4; command='L'; } else if(cmd_run[0]!='\0') { log_critical("Syntax error in command line: %s\n",cmd_run); printf("Syntax error in command line: %s\n",cmd_run); } } switch(command) { case 'L': for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) interface_list(element_disk->disk, verbose, saveheader, create_backup); break; case 'q': case 'Q': done = 1; break; } } cmd_device=NULL; cmd_run=NULL; write_used=delete_list_disk(list_disk); log_info("TestDisk exited normally.\n"); if(log_close()!=0) { printf("TestDisk: Log file corrupted!\n"); } if(write_used!=0) { printf("You have to reboot for the change to take effect.\n"); } #ifdef SUDO_BIN if(use_sudo>0) { printf("\n"); if(use_sudo>1) printf("No disk found.\n"); printf("TestDisk will try to restart itself using the sudo command to get\n"); printf("root (superuser) privileges.\n"); printf("\n"); run_sudo(argc, argv); } #endif return 0; }
int exFAT_boot_sector(disk_t *disk, partition_t *partition, const int verbose, char **current_cmd) { unsigned char *buffer_bs; unsigned char *buffer_backup_bs; const char *options=""; int rescan=1; #ifdef HAVE_NCURSES struct MenuItem menu_exFAT[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q', "Quit","Return to Advanced menu"}, { 'O', "Org. BS","Copy superblock over backup sector"}, { 'B', "Backup BS","Copy backup superblock over superblock"}, { 'D', "Dump","Dump superblock and backup superblock"}, { 0, NULL, NULL } }; #endif buffer_bs=(unsigned char*)MALLOC(12 * disk->sector_size); buffer_backup_bs=(unsigned char*)MALLOC(12 * disk->sector_size); while(1) { #ifdef HAVE_NCURSES unsigned int menu=0; #endif int command; screen_buffer_reset(); if(rescan==1) { int opt_over=0; int opt_B=0; int opt_O=0; options="D"; #ifdef HAVE_NCURSES aff_copy(stdscr); wmove(stdscr,4,0); wprintw(stdscr,"%s",disk->description(disk)); mvwaddstr(stdscr,5,0,msg_PART_HEADER_LONG); wmove(stdscr,6,0); aff_part(stdscr,AFF_PART_ORDER|AFF_PART_STATUS,disk,partition); #endif log_info("\nexFAT_boot_sector\n"); log_partition(disk,partition); screen_buffer_add("Boot sector\n"); if(disk->pread(disk, buffer_bs, 12 * disk->sector_size, partition->part_offset) != 12 * disk->sector_size) { screen_buffer_add("Bad: can't read exFAT boot record.\n"); memset(buffer_bs,0,12 * disk->sector_size); } else if(test_EXFAT((const struct exfat_super_block*)buffer_bs, partition)==0) { screen_buffer_add("exFAT OK\n"); opt_O=1; opt_over=1; } else screen_buffer_add("Bad\n"); screen_buffer_add("\nBackup boot record\n"); if(disk->pread(disk, buffer_backup_bs, 12 * disk->sector_size, partition->part_offset + 12 * disk->sector_size) != 12 * disk->sector_size) { screen_buffer_add("Bad: can't read exFAT backup boot record.\n"); memset(buffer_backup_bs,0,12 * disk->sector_size); } else if(test_EXFAT((const struct exfat_super_block*)buffer_backup_bs, partition)==0) { screen_buffer_add("exFAT OK\n"); opt_B=1; opt_over=1; } else screen_buffer_add("Bad\n"); screen_buffer_add("\n"); if(memcmp(buffer_bs,buffer_backup_bs,12 * disk->sector_size)==0) { screen_buffer_add("Sectors are identical.\n"); opt_over=0; } else { screen_buffer_add("Sectors are not identical.\n"); } if(opt_over!=0) { if(opt_B!=0 && opt_O!=0) options="DOB"; else if(opt_B!=0) options="DB"; else if(opt_O!=0) options="DO"; } rescan=0; } screen_buffer_to_log(); if(*current_cmd!=NULL) { command=0; while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"dump",4)==0) { (*current_cmd)+=4; command='D'; } else if(strncmp(*current_cmd,"originalexFAT",11)==0) { (*current_cmd)+=11; if(strchr(options,'O')!=NULL) command='O'; } else if(strncmp(*current_cmd,"backupexFAT",9)==0) { (*current_cmd)+=9; if(strchr(options,'B')!=NULL) command='B'; } } else { log_flush(); #ifdef HAVE_NCURSES command=screen_buffer_display_ext(stdscr, options, menu_exFAT, &menu); #else command=0; #endif } switch(command) { case 0: free(buffer_bs); free(buffer_backup_bs); return 0; case 'O': /* O : copy original superblock over backup boot */ #ifdef HAVE_NCURSES if(ask_confirmation("Copy original exFAT boot record over backup, confirm ? (Y/N)")!=0) { log_info("copy original superblock over backup boot\n"); if(disk->pwrite(disk, buffer_bs, 12 * disk->sector_size, partition->part_offset + 12 * disk->sector_size) != 12 * disk->sector_size) { display_message("Write error: Can't overwrite exFAT backup boot record\n"); } disk->sync(disk); rescan=1; } #endif break; case 'B': /* B : copy backup superblock over main superblock */ #ifdef HAVE_NCURSES if(ask_confirmation("Copy backup exFAT boot record over main boot record, confirm ? (Y/N)")!=0) { log_info("copy backup superblock over main superblock\n"); /* Reset information about backup boot record */ partition->sb_offset=0; if(disk->pwrite(disk, buffer_backup_bs, 12 * disk->sector_size, partition->part_offset) != 12 * disk->sector_size) { display_message("Write error: Can't overwrite exFAT main boot record\n"); } disk->sync(disk); rescan=1; } #endif break; case 'D': exFAT_dump(disk, partition, buffer_bs, buffer_backup_bs, current_cmd); break; } } }
int dir_partition(disk_t *disk_car, const partition_t *partition, const int verbose, char **current_cmd) { dir_data_t dir_data; #ifdef HAVE_NCURSES WINDOW *window; #endif int res=-3; fflush(stderr); dir_data.local_dir=NULL; if(is_part_fat(partition)) res=dir_partition_fat_init(disk_car,partition,&dir_data,verbose); else if(is_part_ntfs(partition)) { res=dir_partition_ntfs_init(disk_car,partition,&dir_data,verbose); if(res!=0) res=dir_partition_exfat_init(disk_car, partition, &dir_data, verbose); } else if(is_part_linux(partition)) { res=dir_partition_ext2_init(disk_car,partition,&dir_data,verbose); if(res!=0) res=dir_partition_reiser_init(disk_car,partition,&dir_data,verbose); } if(res!=0) { switch(partition->upart_type) { case UP_FAT12: case UP_FAT16: case UP_FAT32: res=dir_partition_fat_init(disk_car,partition,&dir_data,verbose); break; case UP_EXT4: case UP_EXT3: case UP_EXT2: res=dir_partition_ext2_init(disk_car,partition,&dir_data,verbose); break; case UP_RFS: case UP_RFS2: case UP_RFS3: res=dir_partition_reiser_init(disk_car,partition,&dir_data,verbose); break; case UP_NTFS: res=dir_partition_ntfs_init(disk_car,partition,&dir_data,verbose); break; case UP_EXFAT: res=dir_partition_exfat_init(disk_car, partition, &dir_data, verbose); break; default: return res; } } #ifdef HAVE_NCURSES window=newwin(LINES, COLS, 0, 0); /* full screen */ dir_data.display=window; aff_copy(window); #else dir_data.display=NULL; #endif log_info("\n"); switch(res) { case -2: screen_buffer_reset(); #ifdef HAVE_NCURSES aff_copy(window); wmove(window,4,0); aff_part(window,AFF_PART_ORDER|AFF_PART_STATUS,disk_car,partition); #endif log_partition(disk_car,partition); screen_buffer_add("Support for this filesystem hasn't been enable during compilation.\n"); screen_buffer_to_log(); if(*current_cmd==NULL) { #ifdef HAVE_NCURSES screen_buffer_display(window,"",NULL); #endif } break; case -1: screen_buffer_reset(); #ifdef HAVE_NCURSES aff_copy(window); wmove(window,4,0); aff_part(window,AFF_PART_ORDER|AFF_PART_STATUS,disk_car,partition); #endif log_partition(disk_car,partition); screen_buffer_add("Can't open filesystem. Filesystem seems damaged.\n"); screen_buffer_to_log(); if(*current_cmd==NULL) { #ifdef HAVE_NCURSES screen_buffer_display(window,"",NULL); #endif } break; default: { int recursive=0; if(*current_cmd!=NULL) { int do_continue; do { do_continue=0; while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"recursive",9)==0) { (*current_cmd)+=9; recursive=1; do_continue=1; } else if(strncmp(*current_cmd,"fullpathname",12)==0) { (*current_cmd)+=12; dir_data.param|=FLAG_LIST_PATHNAME; do_continue=1; } } while(do_continue==1); } if(recursive>0) dir_whole_partition_log(disk_car,partition,&dir_data,dir_data.current_inode); else { #ifdef HAVE_NCURSES dir_partition_aff(disk_car, partition, &dir_data, dir_data.current_inode, current_cmd); #else { file_data_t *dir_list; dir_list=dir_data.get_dir(disk_car, partition, &dir_data, dir_data.current_inode); dir_aff_log(&dir_data, dir_list); delete_list_file(dir_list); } #endif } dir_data.close(&dir_data); } break; } #ifdef HAVE_NCURSES delwin(window); (void) clearok(stdscr, TRUE); #ifdef HAVE_TOUCHWIN touchwin(stdscr); #endif wrefresh(stdscr); #endif fflush(stderr); free(dir_data.local_dir); return res; }
int ntfs_boot_sector(disk_t *disk_car, partition_t *partition, const int verbose, const unsigned int expert, char **current_cmd) { unsigned char *buffer_bs; unsigned char *buffer_backup_bs; const char *options=""; #ifdef HAVE_NCURSES struct MenuItem menu_ntfs[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q', "Quit","Return to Advanced menu"}, { 'L', "List", "List directories and files, copy data from NTFS" }, { 'O', "Org. BS","Copy boot sector over backup sector"}, { 'B', "Backup BS","Copy backup boot sector over boot sector"}, { 'R', "Rebuild BS","Rebuild boot sector"}, { 'M', "Repair MFT","Check MFT"}, { 'D', "Dump","Dump boot sector and backup boot sector"}, { 0, NULL, NULL } }; #endif buffer_bs=(unsigned char*)MALLOC(NTFS_BOOT_SECTOR_SIZE); buffer_backup_bs=(unsigned char*)MALLOC(NTFS_BOOT_SECTOR_SIZE); while(1) { unsigned int menu=0; int command; screen_buffer_reset(); { int identical_sectors=0; int opt_B=0; int opt_O=0; #ifdef HAVE_NCURSES 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); #endif log_info("\nntfs_boot_sector\n"); log_partition(disk_car,partition); screen_buffer_add("Boot sector\n"); if(disk_car->pread(disk_car, buffer_bs, NTFS_BOOT_SECTOR_SIZE, partition->part_offset) != NTFS_BOOT_SECTOR_SIZE) { screen_buffer_add("ntfs_boot_sector: Can't read boot sector.\n"); memset(buffer_bs,0,NTFS_BOOT_SECTOR_SIZE); } if(test_NTFS(disk_car,(struct ntfs_boot_sector*)buffer_bs,partition,verbose,0)==0) { screen_buffer_add("Status: OK\n"); opt_O=1; } else { screen_buffer_add("Status: Bad\n"); } screen_buffer_add("\nBackup boot sector\n"); if(disk_car->pread(disk_car, buffer_backup_bs, NTFS_BOOT_SECTOR_SIZE, partition->part_offset + partition->part_size - disk_car->sector_size) != NTFS_BOOT_SECTOR_SIZE) { screen_buffer_add("ntfs_boot_sector: Can't read backup boot sector.\n"); memset(buffer_backup_bs,0,NTFS_BOOT_SECTOR_SIZE); } if(test_NTFS(disk_car,(struct ntfs_boot_sector*)buffer_backup_bs,partition,verbose,0)==0) { screen_buffer_add("Status: OK\n"); opt_B=1; } else { screen_buffer_add("Status: Bad\n"); } screen_buffer_add("\n"); if(memcmp(buffer_bs,buffer_backup_bs,NTFS_BOOT_SECTOR_SIZE)==0) { log_ntfs_info((const struct ntfs_boot_sector *)buffer_bs); screen_buffer_add("Sectors are identical.\n"); identical_sectors=1; } else { log_ntfs2_info((const struct ntfs_boot_sector *)buffer_bs, (const struct ntfs_boot_sector *)buffer_backup_bs); screen_buffer_add("Sectors are not identical.\n"); identical_sectors=0; } screen_buffer_add("\n"); screen_buffer_add("A valid NTFS Boot sector must be present in order to access\n"); screen_buffer_add("any data; even if the partition is not bootable.\n"); if(opt_B!=0 && opt_O!=0) { if(identical_sectors==0) options="DOBRL"; else options="DRML"; } else if(opt_B!=0) { menu=5; if(expert>0) options="DBRML"; else options="DBRL"; } else if(opt_O!=0) { menu=4; options="DORL"; } else options="DR"; } screen_buffer_to_log(); if(*current_cmd!=NULL) { command=0; while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"rebuildbs",9)==0) { (*current_cmd)+=9; command='R'; } else if(strncmp(*current_cmd,"dump",4)==0) { (*current_cmd)+=4; command='D'; } else if(strncmp(*current_cmd,"list",4)==0) { (*current_cmd)+=4; command='L'; } else if(strncmp(*current_cmd,"originalntfs",11)==0) { (*current_cmd)+=11; if(strchr(options,'O')!=NULL) command='O'; } else if(strncmp(*current_cmd,"backupntfs",9)==0) { (*current_cmd)+=9; if(strchr(options,'B')!=NULL) command='B'; } else if(strncmp(*current_cmd,"repairmft",9)==0) { (*current_cmd)+=9; if(strchr(options,'M')!=NULL) command='M'; } } else { log_flush(); #ifdef HAVE_NCURSES command=screen_buffer_display_ext(stdscr, options, menu_ntfs, &menu); #else command=0; #endif } switch(command) { case 0: free(buffer_bs); free(buffer_backup_bs); return 0; case 'O': /* O : copy original boot sector over backup boot */ #ifdef HAVE_NCURSES if(ask_confirmation("Copy original NTFS boot sector over backup boot, confirm ? (Y/N)")!=0) { log_info("copy original boot sector over backup boot\n"); if(disk_car->pwrite(disk_car, buffer_bs, NTFS_BOOT_SECTOR_SIZE, partition->part_offset + partition->part_size - disk_car->sector_size) != NTFS_BOOT_SECTOR_SIZE) { display_message("Write error: Can't overwrite NTFS backup boot sector\n"); } disk_car->sync(disk_car); } #endif break; case 'B': /* B : copy backup boot sector over boot sector */ #ifdef HAVE_NCURSES if(ask_confirmation("Copy backup NTFS boot sector over boot sector, confirm ? (Y/N)")!=0) { log_info("copy backup boot sector over boot sector\n"); /* Reset information about backup boot sector */ partition->sb_offset=0; if(disk_car->pwrite(disk_car, buffer_backup_bs, NTFS_BOOT_SECTOR_SIZE, partition->part_offset) != NTFS_BOOT_SECTOR_SIZE) { display_message("Write error: Can't overwrite NTFS boot sector\n"); } disk_car->sync(disk_car); } #endif break; case 'L': if(strchr(options,'O')==NULL && strchr(options,'B')!=NULL) { io_redir_add_redir(disk_car,partition->part_offset,NTFS_BOOT_SECTOR_SIZE,0,buffer_backup_bs); dir_partition(disk_car, partition, 0,current_cmd); io_redir_del_redir(disk_car,partition->part_offset); } else dir_partition(disk_car, partition, 0,current_cmd); break; case 'M': repair_MFT(disk_car, partition, verbose, expert, current_cmd); break; case 'R': /* R : rebuild boot sector */ rebuild_NTFS_BS(disk_car, partition, verbose, 1, expert, current_cmd); break; case 'D': dump_NTFS(disk_car, partition, buffer_bs, buffer_backup_bs); break; } } }