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 *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; }