/* File: intrface.c Copyright (C) 1998-2007 Christophe GRENIER This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #include "types.h" #include "common.h" #include "lang.h" #include "intrf.h" #include "intrfn.h" #include "intrface.h" #include "godmode.h" #include "fnctdsk.h" #include "testdisk.h" #include "adv.h" #include "analyse.h" #include "chgtype.h" #include "edit.h" #include "savehdr.h" #include "dirpart.h" #include "fat.h" #include "partauto.h" #include "log.h" #define INTER_DISK_X 0 #define INTER_DISK_Y 7 extern const arch_fnct_t arch_i386; static void interface_options(int *dump_ind, int *align, int *allow_partial_last_cylinder, unsigned int *expert, char**current_cmd); static list_part_t *interface_load(disk_t *disk_car,list_part_t *list_part, const int debug); static list_part_t *backup_merge(list_part_t *list_part,list_part_t *backup_part, const int debug); static int write_MBR_code(disk_t *disk_car, char **current_cmd); static int write_clean_table(disk_t *disk_car, char **current_cmd); static int interface_check_disk_capacity(disk_t *disk_car); static list_part_t *interface_analyse(disk_t *disk_car, const int debug, const int saveheader, char**current_cmd); static int menu_disk(disk_t *disk_car, const int debug,int dump_ind, const int saveheader, char **current_cmd); void interface_list(disk_t *disk_car, const int debug,const int test_recovery, const int saveheader, const int backup) { list_part_t *list_part; log_info("\nAnalyse "); log_info("%s\n",disk_car->description(disk_car)); printf("%s\n",disk_car->description(disk_car)); printf(msg_PART_HEADER_LONG); list_part=disk_car->arch->read_part(disk_car,debug,saveheader); aff_buffer(BUFFER_WRITE,"Q"); if(backup>0) { partition_save(disk_car,list_part,debug); } if(test_recovery>0) { list_part_t *element; log_info("rebuild_FAT_BS()\n"); for(element=list_part;element!=NULL;element=element->next) { if(is_fat(element->part)) { log_partition(disk_car,element->part); rebuild_FAT_BS(disk_car,element->part,debug,0,0,0,NULL); /* dump_ind */ } /* TODO ntfs */ } } delete_list_part(list_part); } static int write_MBR_code(disk_t *disk_car, char **current_cmd) { aff_copy(stdscr); wmove(stdscr,5,0); wdoprintf(stdscr,"%s\n",disk_car->description(disk_car)); wmove(stdscr,INTER_DISK_Y,INTER_DISK_X); if(disk_car->arch->write_MBR_code==NULL) { display_message("Function to write a new MBR code not implemented for this partition type.\n"); return 1; } wdoprintf(stdscr,msg_WRITE_MBR_CODE); if(ask_YN(stdscr)!=0 && ask_confirmation("Write a new copy of MBR code, confirm ? (Y/N)")!=0) { if(disk_car->arch->write_MBR_code(disk_car)) { display_message("Write error: Can't write new MBR code.\n"); return 2; } else display_message("A new copy of MBR code has been written.\nYou have to reboot for the change to take effect.\n"); } return 0; } int write_clean_table(disk_t *disk_car, char**current_cmd) { aff_copy(stdscr); wmove(stdscr,5,0); wdoprintf(stdscr,"%s\n",disk_car->description(disk_car)); wmove(stdscr,INTER_DISK_Y,INTER_DISK_X); if(disk_car->arch->erase_list_part==NULL) { display_message("Clear partition table not implemented for this partition type.\n"); return 1; } wdoprintf(stdscr,msg_WRITE_CLEAN_TABLE); if(ask_YN(stdscr)!=0 && ask_confirmation("Clear partition table, confirm ? (Y/N)")!=0) { if(disk_car->arch->erase_list_part(disk_car)) { display_message("Write error: Can't clear partition table.\n"); return 2; } else display_message("Partition table has been cleared.\nYou have to reboot for the change to take effect.\n"); } return 0; } static int menu_disk(disk_t *disk_car, const int debug,int dump_ind, const int saveheader, char **current_cmd) { int align=2; int allow_partial_last_cylinder=0; int ask_part_order=0; int command; int done=0; unsigned int menu=0; int real_key; unsigned int expert=0; char options[16]; static struct MenuItem menuMain[]= { {'A',"Analyse","Analyse current partition structure and search for lost partitions"}, {'T',"Advanced","Filesystem Utils"}, {'G',"Geometry", "Change disk geometry" }, {'O',"Options","Modify options"}, {'C',"MBR Code","Write TestDisk MBR code to first sector"}, {'D',"Delete","Delete all data in the partition table"}, {'Q',"Quit","Return to disk selection"}, {'E',"Editor","Basic disk editor"}, {0,NULL,NULL} }; strcpy(options, "AGOPTQ"); if(disk_car->arch->write_MBR_code!=NULL) strcat(options,"C"); if(disk_car->arch->erase_list_part!=NULL) strcat(options,"D"); while(done==0) { aff_copy(stdscr); wmove(stdscr,5,0); wdoprintf(stdscr,"%s\n",disk_car->description(disk_car)); wmove(stdscr,20,0); wdoprintf(stdscr,"Note: Correct disk geometry is required for a successful recovery. 'Analyse'"); wmove(stdscr,21,0); wdoprintf(stdscr,"process may give some warnings if it thinks the logical geometry is mismatched."); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"analyze",7)==0 || strncmp(*current_cmd,"analyse",7)==0) { (*current_cmd)+=7; command='A'; } else if(strncmp(*current_cmd,"geometry",8)==0) { (*current_cmd)+=8; command='G'; } else if(strncmp(*current_cmd,"advanced",8)==0) { (*current_cmd)+=8; command='T'; } else if(strncmp(*current_cmd,"options",7)==0) { (*current_cmd)+=7; command='O'; } else if(strncmp(*current_cmd,"delete",6)==0) { (*current_cmd)+=6; command='D'; } else if(strncmp(*current_cmd,"mbr_code",8)==0) { (*current_cmd)+=8; command='C'; } else { command='Q'; } } else command = wmenuSelect_ext(stdscr,INTER_DISK_Y, INTER_DISK_X, menuMain, 10, options, MENU_VERT | MENU_VERT_WARN | MENU_BUTTON | MENU_ACCEPT_OTHERS, &menu,&real_key); /* e for editor will be added when the editor will be better */ switch(command) { case 'a': case 'A': { int search_vista_part=0; list_part_t *list_part; list_part=interface_analyse(disk_car, debug, saveheader, current_cmd); if(disk_car->arch==&arch_i386) { const int old_allow_partial_last_cylinder=allow_partial_last_cylinder; const list_part_t *element; for(element=list_part;element!=NULL;element=element->next) { if(element->part->part_offset%(2048*512)==0 && element->part->part_size%(2048*512)==0) search_vista_part=1; } if(search_vista_part==0) { if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"mode_vista",10)==0) { (*current_cmd)+=10; search_vista_part=1; } } else { log_info("Ask the user for vista mode\n"); if(ask_confirmation("Should TestDisk search for partition created under Vista ? [Y/N] (answer Yes if unsure)")!=0) search_vista_part=1; } } if(search_vista_part==1) allow_partial_last_cylinder=1; if(old_allow_partial_last_cylinder!=allow_partial_last_cylinder) hd_update_geometry(disk_car,allow_partial_last_cylinder,debug); log_info("Allow partial last cylinder : %s\n", allow_partial_last_cylinder>0?"Yes":"No"); log_info("search_vista_part: %d\n", search_vista_part); } interface_recovery(disk_car, list_part, debug, dump_ind, align, ask_part_order, expert, search_vista_part, current_cmd); delete_list_part(list_part); } break; case 'd': case 'D': write_clean_table(disk_car,current_cmd); break; case 'c': case 'C': write_MBR_code(disk_car,current_cmd); break; case 'g': case 'G': change_geometry(disk_car,current_cmd); break; case 'o': case 'O': { const int old_allow_partial_last_cylinder=allow_partial_last_cylinder; interface_options(&dump_ind, &align,&allow_partial_last_cylinder,&expert,current_cmd); if(old_allow_partial_last_cylinder!=allow_partial_last_cylinder) hd_update_geometry(disk_car,allow_partial_last_cylinder,debug); } break; case 't': case 'T': interface_adv(disk_car, debug, dump_ind, expert,current_cmd); break; case 'q': case 'Q': done = 1; break; case 'e': case 'E': interface_editor(disk_car); break; } } return 0; } int do_curses_testdisk(int debug,int dump_ind, const list_disk_t *list_disk, const int saveheader, const char *cmd_device, char **current_cmd) { int command='Q'; int allow_partial_last_cylinder=0; int done=0; unsigned int menu=0; int offset=0; int pos_num=0; const list_disk_t *element_disk; const list_disk_t *current_disk=NULL; static struct MenuItem menuMain[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'O',"Proceed",""}, { 'Q',"Quit","Quit program"}, { 0,NULL,NULL} }; if(cmd_device!=NULL) { for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next) { if(strcmp(element_disk->disk->device,cmd_device)==0) current_disk=element_disk; } } else current_disk=list_disk; if(current_disk==NULL) { intrf_no_disk("TestDisk"); return 0; } /* ncurses interface */ while(done==0) { const char *options; int i; aff_copy(stdscr); wmove(stdscr,4,0); wdoprintf(stdscr," TestDisk is free software, and"); wmove(stdscr,5,0); wdoprintf(stdscr,"comes with ABSOLUTELY NO WARRANTY."); wmove(stdscr,7,0); wdoprintf(stdscr,"Select a media (use Arrow keys, then press Enter):"); /* TODO: Detect the LBA28 limitation */ for(i=0,element_disk=list_disk;(element_disk!=NULL) && (inext,i++); for(;element_disk!=NULL && (i-offset)<10;i++,element_disk=element_disk->next) { wmove(stdscr,8+i-offset,0); if(element_disk!=current_disk) wdoprintf(stdscr,"%s\n",element_disk->disk->description_short(element_disk->disk)); else { wattrset(stdscr, A_REVERSE); wdoprintf(stdscr,"%s\n",element_disk->disk->description_short(element_disk->disk)); wattroff(stdscr, A_REVERSE); } } if(i<=10 && element_disk==NULL) options="OQ"; else options="PNOQ"; { int line=20; #if defined(__CYGWIN__) || defined(__MINGW32__) #else #ifndef DJGPP #ifdef HAVE_GETEUID if(geteuid()!=0) { wmove(stdscr,line++,0); wdoprintf(stdscr,"Note: Some disks won't appear unless you're root user."); } #endif #endif #endif wmove(stdscr,line++,0); if(line==22) wdoprintf(stdscr,"Disk capacity must be correctly detected for a successful recovery."); else wdoprintf(stdscr,"Note: Disk capacity must be correctly detected for a successful recovery."); wmove(stdscr,line++,0); wdoprintf(stdscr,"If a disk listed above has incorrect size, check HD jumper settings, BIOS"); wmove(stdscr,line++,0); wdoprintf(stdscr,"detection, and install the latest OS patches and disk drivers."); } if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; if(*current_cmd[0]=='\0') command='Q'; else if(strncmp(*current_cmd,"inter",4)==0) { cmd_device=NULL; *current_cmd=NULL; } else { if(command=='O') command='Q'; else command='O'; } } if(*current_cmd==NULL) command = wmenuSelect_ext(stdscr,INTER_MAIN_Y, INTER_MAIN_X, menuMain, 8, options, MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, &menu,NULL); switch(command) { case KEY_UP: case 'P': if(current_disk->prev!=NULL) { current_disk=current_disk->prev; pos_num--; } if(pos_numnext!=NULL) { current_disk=current_disk->next; pos_num++; } if(pos_num>=offset+10) offset++; break; case KEY_PPAGE: for(i=0;iprev!=NULL;i++) { current_disk=current_disk->prev; pos_num--; if(pos_numnext!=NULL;i++) { current_disk=current_disk->next; pos_num++; if(pos_num>=offset+10) offset++; } break; case 'o': case 'O': { disk_t *disk=current_disk->disk; autodetect_arch(disk); if(interface_check_disk_capacity(disk)==0 && interface_partition_type(disk, allow_partial_last_cylinder, debug, current_cmd)==0) { if(menu_disk(disk, debug, dump_ind, saveheader, current_cmd)) done=1; } } break; case 'q': case 'Q': done=1; break; } } return 0; } static int interface_check_disk_capacity(disk_t *disk_car) { /* Test for LBA28 limitation */ if(disk_car->CHS.sector>0 && (disk_car->CHS.cylinder+1) == (((1<<28)-1) / (disk_car->CHS.head+1) / disk_car->CHS.sector)) { static const struct MenuItem menuMain[]= { { 'C', "Continue","The HD is really 137 GB only."}, { 'Q',"Quit","The HD is bigger, it's safer to enable LBA48 support first."}, { 0,NULL,NULL} }; unsigned int menu=1; int car; log_warning("LBA28 limitation\n"); aff_copy(stdscr); if(disk_car->arch->msg_part_type!=NULL) mvwaddstr(stdscr,22,0,disk_car->arch->msg_part_type); wmove(stdscr,4,0); wdoprintf(stdscr,"%s\n",disk_car->description(disk_car)); wmove(stdscr,6,0); wdoprintf(stdscr,"The Harddisk size seems to be 137GB."); wmove(stdscr,7,0); wdoprintf(stdscr,"Support for 48-bit Logical Block Addressing (LBA) is needed to access"); wmove(stdscr,8,0); wdoprintf(stdscr,"hard disks larger than 137 GB."); wmove(stdscr,9,0); #if defined(__CYGWIN__) || defined(__MINGW32__) wdoprintf(stdscr,"Update Windows to support LBA48 (minimum: W2K SP4 or XP SP1)"); #endif car= wmenuSelect_ext(stdscr,INTER_MAIN_Y, INTER_MAIN_X, menuMain, 10, "CQ", MENU_VERT | MENU_VERT_WARN | MENU_BUTTON, &menu,NULL); if(car=='c' || car=='C') return 0; return 1; } return 0; } static list_part_t *interface_analyse(disk_t *disk_car, const int debug, const int saveheader, char**current_cmd) { list_part_t *list_part; int command; struct MenuItem menuAnalyse[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q',"Proceed","Try to locate partition"}, { 'B', "Backup","Save current partition list to backup.log file and proceed"}, { 0, NULL, NULL } }; log_info("\nAnalyse "); log_info("%s\n",disk_car->description(disk_car)); aff_buffer(BUFFER_RESET,"Q"); /* ncurses interface */ aff_copy(stdscr); if(disk_car->arch->msg_part_type!=NULL) mvwaddstr(stdscr,22,0,disk_car->arch->msg_part_type); wmove(stdscr,4,0); wdoprintf(stdscr,"%s\n",disk_car->description(disk_car)); mvwaddstr(stdscr,5,0,"Checking current partition structure"); wmove(stdscr,6,0); wrefresh(stdscr); wdoprintf(stdscr,msg_PART_HEADER_LONG); list_part=disk_car->arch->read_part(disk_car,debug,saveheader); wmove(stdscr,5,0); wclrtoeol(stdscr); /* before addstr for BSD compatibility */ waddstr(stdscr,"Current partition structure:"); log_info("Current partition structure:\n"); if(*current_cmd!=NULL) { command='Q'; while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"backup",6)==0) { (*current_cmd)+=6; if(list_part!=NULL) command='B'; } screen_buffer_to_log(); } else command=screen_buffer_display(stdscr,(list_part!=NULL?"QB":"Q"),menuAnalyse); if(command=='B') { log_info("Backup partition structure\n"); if(partition_save(disk_car,list_part,debug)<0) { display_message("Can't create backup.log.\n"); } } return list_part; } int interface_write(disk_t *disk_car,list_part_t *list_part,const int can_search_deeper, const int can_ask_minmax_ext, int *no_confirm, char **current_cmd, unsigned int *menu) { list_part_t *parts; struct MenuItem menuWrite[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q', "Quit","Return to main menu"}, { 'S', "Search!","Search deeper, try to find more partitions"}, { 'W', "Write","Write partition structure to disk"}, { 'E', "Extd Part","Maximize/Minimize extended partition"}, { 0, NULL, NULL } }; int command; log_info("\ninterface_write()\n"); aff_buffer(BUFFER_RESET,"Q"); aff_copy(stdscr); wmove(stdscr,4,0); wdoprintf(stdscr,"%s",disk_car->description(disk_car)); wmove(stdscr,5,0); mvwaddstr(stdscr,6,0,msg_PART_HEADER_LONG); for(parts=list_part;parts!=NULL;parts=parts->next) if(parts->part->status!=STATUS_LOG) aff_part_buffer(AFF_PART_ORDER,disk_car,parts->part); for(parts=list_part;parts!=NULL;parts=parts->next) if(parts->part->status==STATUS_LOG) aff_part_buffer(AFF_PART_ORDER,disk_car,parts->part); if(list_part==NULL) { aff_buffer(BUFFER_ADD," \nNo partition found or selected for recovery"); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"search",6)==0) { (*current_cmd)+=6; command='S'; } else command='Q'; screen_buffer_to_log(); } else command=screen_buffer_display_ext(stdscr,(can_search_deeper?"S":""),menuWrite,menu); } else { if(*current_cmd!=NULL) { do { while(*current_cmd[0]==',') (*current_cmd)++; command='Q'; if(strncmp(*current_cmd,"search",6)==0) { (*current_cmd)+=6; if(can_search_deeper) command='S'; } else if(strncmp(*current_cmd,"noconfirm",9)==0) { command=0; /* do nothing */ (*no_confirm)=1; (*current_cmd)+=9; } else if(strncmp(*current_cmd,"write",5)==0) { (*current_cmd)+=5; if(disk_car->arch->write_part!=NULL) command='W'; } } while(command==0); screen_buffer_to_log(); } else { char options[10]; options[0]=0; if(can_search_deeper) strcat(options,"S"); if(disk_car->arch->write_part!=NULL) strcat(options,"W"); else aff_buffer(BUFFER_ADD," \nWrite isn't available because the partition table type \"%s\" has been selected.", disk_car->arch->part_name); if(can_ask_minmax_ext) strcat(options,"E"); command=screen_buffer_display_ext(stdscr,options,menuWrite,menu); } } return command; } static void interface_options(int *dump_ind, int *align, int *allow_partial_last_cylinder, unsigned int *expert, char**current_cmd) { /* paranoid: search in partition * dump_ind dump sector Y/N * */ if(*current_cmd!=NULL) { int keep_asking=1; do { while(*current_cmd[0]==',') (*current_cmd)++; keep_asking=0; } while(keep_asking>0); } else { int done = FALSE; unsigned int menu = 4; /* ncurses interface */ while (done==FALSE) { int car; int real_key; struct MenuItem menuOptions[]= { { 'E',NULL,"Expert mode adds some functionalities"}, { 'C',NULL,"Partitions are aligned on cylinder/head boundaries" }, { 'A',NULL,""}, { 'D',NULL,"Dump essential sectors" }, { 'Q',"[ Ok ]","Done with changing options"}, { 0, NULL, NULL } }; menuOptions[0].name=*expert?"Expert mode : Yes":"Expert mode : No"; switch(*align) { case 0: menuOptions[1].name="Cylinder boundary : No"; break; case 1: menuOptions[1].name="Cylinder boundary : Head boundary only"; break; case 2: menuOptions[1].name="Cylinder boundary : Yes"; break; } menuOptions[2].name=*allow_partial_last_cylinder?"Allow partial last cylinder : Yes":"Allow partial last cylinder : No"; menuOptions[3].name=*dump_ind?"Dump : Yes":"Dump : No"; aff_copy(stdscr); car=wmenuSelect_ext(stdscr,INTER_OPTION_Y, INTER_OPTION_X, menuOptions, 0, "ECADQ", MENU_VERT|MENU_VERT_ARROW2VALID, &menu,&real_key); switch(car) { case 'd': case 'D': *dump_ind=!*dump_ind; break; case 'c': case 'C': if(*align<2) (*align)++; else *align=0; break; case 'a': case 'A': *allow_partial_last_cylinder=!*allow_partial_last_cylinder; break; case 'e': case 'E': *expert=!*expert; break; case key_ESC: case 'q': case 'Q': done = TRUE; break; } } } /* write new options to log file */ log_info("New options :\n Dump : %s\n ", *dump_ind?"Yes":"No"); switch(*align) { case 0: log_info("Cylinder boundary : No"); break; case 1: log_info("Cylinder boundary : Head boundary only"); break; case 2: log_info("Cylinder boundary : Yes"); break; } log_info("\n Allow partial last cylinder : %s\n Expert mode : %s\n", *allow_partial_last_cylinder?"Yes":"No", *expert?"Yes":"No"); } list_part_t *ask_structure(disk_t *disk_car,list_part_t *list_part, const int debug, char **current_cmd) { int quit=0; int offset=0; int pos_num=0; list_part_t *pos=list_part; int rewrite=1; do { int i; int command; list_part_t *parts; int structure_status; if(rewrite) { aff_copy(stdscr); wmove(stdscr,4,0); wdoprintf(stdscr,"%s",disk_car->description(disk_car)); mvwaddstr(stdscr,5,0,msg_PART_HEADER); rewrite=0; } structure_status=disk_car->arch->test_structure(list_part); for(i=0,parts=list_part;(parts!=NULL) && (inext,i++); for(i=offset;(parts!=NULL) &&((i-offset)next) { wmove(stdscr,6+i-offset,0); wclrtoeol(stdscr); /* before addstr for BSD compatibility */ if(parts==pos) { wattrset(stdscr, A_REVERSE); } if(structure_status==0 && parts->part->status!=STATUS_DELETED && has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(2)); aff_part(stdscr,AFF_PART_NONL,disk_car,parts->part); if(structure_status==0 && parts->part->status!=STATUS_DELETED && has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); if(parts==pos) { char buffer_part_size[100]; wattroff(stdscr, A_REVERSE); wmove(stdscr,24,0); wclrtoeol(stdscr); /* before addstr for BSD compatibility */ if(parts->part->info[0]!='\0') { wdoprintf(stdscr,"%s, ",parts->part->info); } wdoprintf(stdscr,"%s",size_to_unit(parts->part->part_size,buffer_part_size)); } } if(structure_status==0) mvwaddstr(stdscr,19,0,msg_STRUCT_OK); else { if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(1)); mvwaddstr(stdscr,19,0,msg_STRUCT_BAD); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); } if(list_part!=NULL && disk_car->arch->msg_part_type!=NULL) { mvwaddstr(stdscr,19,16,"Use "); if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"Up"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr,"/"); if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"Down"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr," Arrow keys to select partition."); mvwaddstr(stdscr,20,0,"Use "); if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"Left"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr,"/"); if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"Right"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr," Arrow keys to CHANGE partition characteristics:"); mvwaddstr(stdscr,21,0,disk_car->arch->msg_part_type); } wmove(stdscr,22,0); wclrtoeol(stdscr); /* before addstr for BSD compatibility */ waddstr(stdscr,"Keys "); if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"A"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr,": add partition, "); if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"L"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr,": load backup, "); if(list_part==NULL) { waddstr(stdscr,"Enter: to continue"); } else { if(pos->part->arch==NULL || pos->part->arch==disk_car->arch) { if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"T"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr,": change type, "); } switch(pos->part->upart_type) { case UP_EXT2: case UP_EXT3: case UP_RFS: case UP_RFS2: case UP_RFS3: case UP_FAT12: case UP_FAT16: case UP_FAT32: case UP_NTFS: if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); waddstr(stdscr,"P"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr,": list files, "); break; default: break; } if(has_colors()) wbkgdset(stdscr,' ' | A_BOLD | COLOR_PAIR(0)); mvwaddstr(stdscr,23,5, "Enter"); if(has_colors()) wbkgdset(stdscr,' ' | COLOR_PAIR(0)); waddstr(stdscr,": to continue"); } wrefresh(stdscr); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"list",4)==0) { (*current_cmd)+=4; command='p'; } else command='q'; } else command=wgetch(stdscr); switch(command) { case 'q': case '\r': case '\n': case KEY_ENTER: #ifdef PADENTER case PADENTER: #endif case 'M': quit=1; break; case KEY_UP: if(list_part!=NULL) { only_one_bootable(list_part,pos); if(pos->prev!=NULL) { pos=pos->prev; pos_num--; } if(pos_numnext!=NULL) { pos=pos->next; pos_num++; } if(pos_num>=offset+INTER_STRUCTURE) offset++; } break; case KEY_PPAGE: if(list_part!=NULL) { only_one_bootable(list_part,pos); for(i=0;(iprev!=NULL);i++) { pos=pos->prev; pos_num--; if(pos_numnext!=NULL);i++) { pos=pos->next; pos_num++; if(pos_num>=offset+INTER_STRUCTURE) offset++; } } break; case KEY_RIGHT: case '+': case ' ': if(list_part!=NULL) { if(pos->part->arch==NULL || pos->part->arch==disk_car->arch) disk_car->arch->set_next_status(disk_car,pos->part); } break; case KEY_LEFT: case '-': if(list_part!=NULL) { if(pos->part->arch==NULL || pos->part->arch==disk_car->arch) disk_car->arch->set_prev_status(disk_car,pos->part); } break; case 'a': case 'A': { list_part=disk_car->arch->add_partition(disk_car,list_part, debug,current_cmd); rewrite=1; offset=0; pos_num=0; pos=list_part; } break; case 't': case 'T': if(list_part!=NULL) { if(pos->part->arch==NULL || pos->part->arch==disk_car->arch) { rewrite=1; change_part_type(disk_car,pos->part,current_cmd); } } break; case 'p': case 'P': if(list_part!=NULL) dir_partition(disk_car,pos->part,debug,current_cmd); break; case 'l': case 'L': list_part=interface_load(disk_car,list_part,debug); rewrite=1; offset=0; pos_num=0; pos=list_part; break; default: /* log_trace("ask_structure command=%x\n",command); */ break; } } while(quit==0); return list_part; } static list_part_t *backup_merge(list_part_t *list_part,list_part_t *backup_part, const int debug) { list_part_t *partition; for(partition=backup_part;partition!=NULL;partition=partition->next) { partition_t *new_partition=partition_new(); dup_partition_t(new_partition,partition->part); list_part=insert_new_partition(list_part, new_partition); } return list_part; } static list_part_t *interface_load(disk_t *disk_car,list_part_t *list_part, const int debug) { struct list_head *backup_walker=NULL; backup_disk_t *backup_list=partition_load(disk_car,debug); { log_info("interface_load\n"); list_for_each(backup_walker,&backup_list->list) { list_part_t *element; backup_disk_t *backup; backup=list_entry(backup_walker, backup_disk_t, list); log_info("%s %s",backup->description,ctime(&backup->my_time)); for(element=backup->list_part;element!=NULL;element=element->next) log_partition(disk_car,element->part); } } { int quit=0; int offset=0; int backup_current_num=0; int rewrite=1; unsigned int menu=3; /* default : quit */ struct list_head *backup_current=backup_list->list.next; struct MenuItem menuLoadBackup[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'L',"Load","Load partition structure from backup and try to locate partition"}, { 'Q',"Cancel","Don't use backup and try to locate partition"}, { 0, NULL, NULL } }; char options[20]; do { int i; if(rewrite) { aff_copy(stdscr); mvwaddstr(stdscr,4,0,disk_car->description(disk_car)); if(backup_list!=NULL) { mvwaddstr(stdscr,5,0,"Choose the backup you want to restore:"); mvwaddstr(stdscr,20,0,"PS: Don't worry you will have to confirm the partition restoration."); } else { mvwaddstr(stdscr,5,0,"No backup found!"); } rewrite=0; } if(backup_list!=NULL) { backup_disk_t *backup=NULL; for(i=0,backup_walker=backup_list->list.next;(backup_walker!=&backup_list->list) && (inext,i++); for(i=offset;(backup_walker!=&backup_list->list) &&((i-offset)next) { backup=list_entry(backup_walker, backup_disk_t, list); wmove(stdscr,8+i-offset,0); wclrtoeol(stdscr); /* before addstr for BSD compatibility */ if(backup_walker==backup_current) { wattrset(stdscr, A_REVERSE); wdoprintf(stdscr,"%s %s",backup->description,ctime(&backup->my_time)); wattroff(stdscr, A_REVERSE); } else { wdoprintf(stdscr,"%s %s",backup->description,ctime(&backup->my_time)); } } if(i<=INTER_STRUCTURE && backup==NULL) { strncpy(options,"LQ",sizeof(options)); menu=0; } else { strncpy(options,"PNLQ",sizeof(options)); menu=2; } } else { menu=0; strncpy(options,"Q",sizeof(options)); } switch(wmenuSelect(stdscr,INTER_DUMP_Y,INTER_DUMP_X, menuLoadBackup, 8, options, MENU_HORIZ| MENU_BUTTON | MENU_ACCEPT_OTHERS, menu)) { case 'q': case 'Q': quit=1; break; case 'l': case 'L': quit=2; break; case KEY_UP: if(backup_current->prev!=&backup_list->list) { backup_current=backup_current->prev; backup_current_num--; if(backup_current_numnext!=&backup_list->list) { backup_current=backup_current->next; backup_current_num++; if(backup_current_num>=offset+INTER_STRUCTURE) offset++; } break; case KEY_PPAGE: { for(i=0;(iprev!=&backup_list->list);i++) { backup_current=backup_current->prev; backup_current_num--; if(backup_current_numnext!=&backup_list->list);i++) { backup_current=backup_current->next; backup_current_num++; if(backup_current_num>=offset+INTER_STRUCTURE) offset++; } } break; default: /* log_trace("ask_structure car=%x\n",car); */ break; } } while(quit==0); if(backup_current!=NULL && quit==2) { list_part_t *partition; backup_disk_t *backup; backup=list_entry(backup_current, backup_disk_t, list); for(partition=backup->list_part;partition!=NULL;partition=partition->next) { /* Check partition and load partition name */ disk_car->arch->check_part(disk_car,debug,partition->part,0); } list_part=backup_merge(list_part,backup->list_part,debug); } } { /* Cleanup */ struct list_head *backup_walker_next = NULL; list_for_each_safe(backup_walker,backup_walker_next,&backup_list->list) { backup_disk_t *backup; backup=list_entry(backup_walker, backup_disk_t, list); delete_list_part(backup->list_part); free(backup); } free(backup_list); } return list_part; } int interface_superblock(disk_t *disk_car,list_part_t *list_part, char**current_cmd) { list_part_t *parts; partition_t *old_part=NULL; struct MenuItem menuSuperblock[]= { { 'P', "Previous",""}, { 'N', "Next","" }, { 'Q',"Quit","Return to Advanced menu"}, { 0, NULL, NULL } }; aff_buffer(BUFFER_RESET,"Q"); aff_copy(stdscr); wmove(stdscr,4,0); wdoprintf(stdscr,"%s",disk_car->description(disk_car)); wmove(stdscr,5,0); mvwaddstr(stdscr,6,0,msg_PART_HEADER_LONG); for(parts=list_part;parts!=NULL;parts=parts->next) { if(old_part==NULL || (old_part->part_offset!=parts->part->part_offset) || old_part->part_size!=parts->part->part_size || old_part->part_type_i386!=parts->part->part_type_i386 || old_part->part_type_sun!=parts->part->part_type_sun || old_part->part_type_mac!=parts->part->part_type_mac || old_part->upart_type!=parts->part->upart_type) { aff_part_buffer(AFF_PART_SHORT,disk_car,parts->part); old_part=parts->part; } aff_buffer(BUFFER_ADD,"superblock %u, blocksize=%u\n",parts->part->boot_sector,parts->part->blocksize); } if(*current_cmd!=NULL) { screen_buffer_to_log(); return 0; } return screen_buffer_display(stdscr,"",menuSuperblock); }