/* File: geometry.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 #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include "types.h" #include "common.h" #include "intrf.h" #include "intrfn.h" #include "chgtype.h" #include "log.h" void change_geometry(disk_t *disk_car, char ** current_cmd) { int done = FALSE; char def[LINE_LENGTH]; char response[LINE_LENGTH]; int tmp_val=0; int command; int default_option=4; int cyl_modified=0; int geo_modified=0; while (done==FALSE) { static struct MenuItem menuGeometry[]= { { 'c', "Cylinders", "Change cylinder geometry" }, { 'h', "Heads", "Change head geometry" }, { 's', "Sectors", "Change sector geometry" }, { 'n', "Sector Size", "Change sector size (WARNING: VERY DANGEROUS!)" }, { 'q', "Ok", "Done with changing geometry" }, { 0, NULL, NULL } }; aff_copy(stdscr); wmove(stdscr,5,0); wdoprintf(stdscr,"%s, sector size=%u\n",disk_car->description(disk_car),disk_car->sector_size); wmove(stdscr,7,0); wdoprintf(stdscr,"Because these numbers change the way that TestDisk looks for partitions"); wmove(stdscr,8,0); wdoprintf(stdscr,"and calculates their sizes, it's important to have the correct disk geometry."); wmove(stdscr,9,0); wdoprintf(stdscr,"PC partitioning programs often make partitions end on cylinder boundaries."); wmove(stdscr,11,0); wdoprintf(stdscr,"A partition's CHS values are based on disk translations which make them"); wmove(stdscr,12,0); wdoprintf(stdscr,"different than its physical geometry. The most common CHS head values"); wmove(stdscr,13,0); wdoprintf(stdscr,"are: 255, 240 and sometimes 16."); wmove(stdscr,INTER_GEOM_Y, INTER_GEOM_X); wclrtoeol(stdscr); wrefresh(stdscr); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; if(strncmp(*current_cmd,"C",1)==0) { (*current_cmd)+=1; command='C'; } else if(strncmp(*current_cmd,"H",1)==0) { (*current_cmd)+=1; command='H'; } else if(strncmp(*current_cmd,"S",1)==0) { (*current_cmd)+=1; command='S'; } else if(strncmp(*current_cmd,"N",1)==0) { (*current_cmd)+=1; command='N'; } else { command='Q'; } } else command=wmenuSimple(stdscr,menuGeometry, default_option); switch (command) { case 'c': case 'C': { int ok=0; sprintf(def, "%u", disk_car->CHS.cylinder+1); mvwaddstr(stdscr,INTER_GEOM_Y, INTER_GEOM_X, "Enter the number of cylinders: "); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; tmp_val = atoi(*current_cmd); while(*current_cmd[0]!=',' && *current_cmd[0]!='\0') (*current_cmd)++; ok=1; } else { if (get_string(response, LINE_LENGTH, def) > 0) { tmp_val = atoi(response); ok=1; } } if(ok>0) { if (tmp_val > 0) { disk_car->CHS.cylinder = tmp_val-1; cyl_modified=1; geo_modified=1; } else wdoprintf(stdscr,"Illegal cylinders value"); } default_option=1; } break; case 'h': case 'H': { int ok=0; sprintf(def, "%u", disk_car->CHS.head+1); mvwaddstr(stdscr,INTER_GEOM_Y, INTER_GEOM_X, "Enter the number of heads: "); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; tmp_val = atoi(*current_cmd); while(*current_cmd[0]!=',' && *current_cmd[0]!='\0') (*current_cmd)++; ok=1; } else { if (get_string(response, LINE_LENGTH, def) > 0) { tmp_val = atoi(response); ok=1; } } if(ok>0) { if (tmp_val > 0 && tmp_val <= MAX_HEADS) { disk_car->CHS.head = tmp_val-1; geo_modified=1; if(cyl_modified==0) { /* Round up */ disk_car->CHS.cylinder=(((disk_car->disk_size/disk_car->sector_size+disk_car->CHS.head)/(disk_car->CHS.head+1))+disk_car->CHS.sector-1)/disk_car->CHS.sector-1; } } else wdoprintf(stdscr,"Illegal heads value"); } default_option=2; } break; case 's': case 'S': { int ok=0; sprintf(def, "%u", disk_car->CHS.sector); mvwaddstr(stdscr,INTER_GEOM_Y, INTER_GEOM_X, "Enter the number of sectors per track (1-63): "); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; tmp_val = atoi(*current_cmd); while(*current_cmd[0]!=',' && *current_cmd[0]!='\0') (*current_cmd)++; ok=1; } else { if (get_string(response, LINE_LENGTH, def) > 0) { tmp_val = atoi(response); ok=1; } } if(ok>0) { /* SUN partition can have more than 63 sectors */ if (tmp_val > 0) { disk_car->CHS.sector = tmp_val; geo_modified=1; if(cyl_modified==0) { disk_car->CHS.cylinder=(disk_car->disk_size/disk_car->sector_size/(disk_car->CHS.head+1))/disk_car->CHS.sector-1; } } else wdoprintf(stdscr,"Illegal sectors value"); } default_option=3; } break; case 'n': case 'N': { int ok=0; sprintf(def, "%u", disk_car->sector_size); mvwaddstr(stdscr,INTER_GEOM_Y, INTER_GEOM_X, "Enter the sector size (512, 1024, 2048, 4096): "); if(*current_cmd!=NULL) { while(*current_cmd[0]==',') (*current_cmd)++; tmp_val = atoi(*current_cmd); while(*current_cmd[0]!=',' && *current_cmd[0]!='\0') (*current_cmd)++; ok=1; } else { if (get_string(response, LINE_LENGTH, def) > 0) { tmp_val = atoi(response); ok=1; } } if(ok>0) { /* FIXME using 3*512=1536 as sector size and */ /* 63/3=21 for number of sectors is an easy way to test */ if (tmp_val==512 || tmp_val==1024 || tmp_val==2048 || tmp_val==4096 || tmp_val==3*512) { disk_car->sector_size = tmp_val; if(cyl_modified==0) { disk_car->CHS.cylinder=(disk_car->disk_size/disk_car->sector_size/(disk_car->CHS.head+1))/disk_car->CHS.sector-1; } } else wdoprintf(stdscr,"Illegal sector size"); } default_option=4; } break; case key_ESC: case 'q': case 'Q': done = TRUE; break; } if(cyl_modified!=0) disk_car->disk_size=(uint64_t)(disk_car->CHS.cylinder+1)*(disk_car->CHS.head+1)*disk_car->CHS.sector*disk_car->sector_size; } if(geo_modified!=0) { disk_car->disk_size=(uint64_t)(disk_car->CHS.cylinder+1)*(disk_car->CHS.head+1)*disk_car->CHS.sector*disk_car->sector_size; #ifdef __APPLE__ /* On MacOSX if HD contains some bad sectors, the disk size may not be correctly detected */ disk_car->disk_real_size=disk_car->disk_size; #endif log_info("New geometry\n%s sector_size=%u\n", disk_car->description(disk_car), disk_car->sector_size); } }