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 int check_part_gpt(disk_t *disk, const int verbose,partition_t *partition, const int saveheader) { int ret=0; unsigned int old_levels; old_levels=log_set_levels(0); if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_MS_BASIC_DATA)==0 || guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_MS_RESERVED)==0) { ret=check_FAT(disk,partition,verbose); if(ret!=0) ret=check_EXFAT(disk, partition); if(ret!=0) ret=check_NTFS(disk,partition,verbose,0); if(ret!=0) ret=check_ReFS(disk, partition); if(ret!=0) ret=check_linux(disk, partition, verbose); if(ret!=0) screen_buffer_add("No FAT, NTFS, ext2, JFS, Reiser, cramfs or XFS marker\n"); } else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_LINUX_RAID)==0) { ret=check_MD(disk, partition, verbose); if(ret!=0) screen_buffer_add("Invalid RAID superblock\n"); } else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_LINUX_LVM)==0) { ret=check_LVM(disk, partition, verbose); if(ret!=0) ret=check_LVM2(disk, partition, verbose); if(ret!=0) screen_buffer_add("No LVM or LVM2 structure\n"); } else if(guid_cmp(partition->part_type_gpt, GPT_ENT_TYPE_MAC_HFS)==0) { ret=check_HFS(disk, partition, verbose); if(ret!=0) ret=check_HFSP(disk, partition, verbose); if(ret!=0) screen_buffer_add("No HFS or HFS+ structure\n"); } log_set_levels(old_levels); if(ret!=0) { log_error("check_part_gpt failed for partition\n"); log_partition(disk, partition); aff_part_buffer(AFF_PART_ORDER|AFF_PART_STATUS,disk,partition); if(saveheader>0) { save_header(disk, partition, verbose); } } return ret; }
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; }
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; }