Пример #1
0
/* Using a couple of inodes of "." directory entries, get the cluster size and where the first cluster begins.
 * */
int find_sectors_per_cluster(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind,const int interface, unsigned int *sectors_per_cluster, uint64_t *offset_org, const upart_type_t upart_type)
{
  unsigned int nbr_subdir=0;
  sector_cluster_t sector_cluster[10];
  uint64_t offset;
  uint64_t skip_offset;
  int ind_stop=0;
  unsigned char *buffer=(unsigned char *)MALLOC(disk_car->sector_size);
#ifdef HAVE_NCURSES
  if(interface)
  {
    wmove(stdscr,22,0);
    wattrset(stdscr, A_REVERSE);
    waddstr(stdscr,"  Stop  ");
    wattroff(stdscr, A_REVERSE);
  }
#endif
  /* 2 fats, maximum cluster size=128 */
  skip_offset=(uint64_t)((partition->part_size-32*disk_car->sector_size)/disk_car->sector_size/128*1.5/disk_car->sector_size*2)*disk_car->sector_size;
  if(verbose>0)
  {
    log_verbose("find_sectors_per_cluster skip_sectors=%lu (skip_offset=%lu)\n",
	(unsigned long)(skip_offset/disk_car->sector_size),
	(unsigned long)skip_offset);
  }
  for(offset=skip_offset;(offset<partition->part_size)&&!ind_stop&&(nbr_subdir<10);offset+=disk_car->sector_size)
  {
#ifdef HAVE_NCURSES
    if(interface>0 && ((offset&(1024*disk_car->sector_size-1))==0))
    {
      wmove(stdscr,9,0);
      wclrtoeol(stdscr);
      wprintw(stdscr,"Search subdirectory %10lu/%lu %u",(unsigned long)(offset/disk_car->sector_size),(unsigned long)(partition->part_size/disk_car->sector_size),nbr_subdir);
      wrefresh(stdscr);
      ind_stop|=check_enter_key_or_s(stdscr);
    }
#endif
    if((unsigned)disk_car->pread(disk_car, buffer, disk_car->sector_size, partition->part_offset + offset) == disk_car->sector_size)
    {
      if(memcmp(&buffer[0],".          ",8+3)==0 && memcmp(&buffer[0x20],"..         ",8+3)==0)
      {
	unsigned long int cluster=(buffer[0*0x20+0x15]<<24) + (buffer[0*0x20+0x14]<<16) +
	  (buffer[0*0x20+0x1B]<<8) + buffer[0*0x20+0x1A];
	log_info("sector %lu, cluster %lu\n",
	    (unsigned long)(offset/disk_car->sector_size), cluster);
	sector_cluster[nbr_subdir].cluster=cluster;
	sector_cluster[nbr_subdir].sector=offset/disk_car->sector_size;
	nbr_subdir++;
#ifdef HAVE_NCURSES
	if(dump_ind>0)
	  dump_ncurses(buffer,disk_car->sector_size);
#endif
      }
    }
  }
  free(buffer);
  return find_sectors_per_cluster_aux(sector_cluster,nbr_subdir,sectors_per_cluster,offset_org,verbose,partition->part_size/disk_car->sector_size, upart_type);
}
Пример #2
0
pstatus_t photorec_progressbar(WINDOW *window, const unsigned int pass, const struct ph_param *params, const uint64_t offset, const time_t current_time)
{
  const partition_t *partition=params->partition;
  const unsigned int sector_size=params->disk->sector_size;
  if(params->status!=STATUS_FIND_OFFSET)
  {
    wmove(window,8,0);
    wclrtoeol(window);
    wprintw(window,"Destination %s", params->recup_dir);
  }
  wmove(window,10,0);
  wclrtoeol(window);
  if(params->status==STATUS_EXT2_ON_BF || params->status==STATUS_EXT2_OFF_BF)
  {
    wprintw(window,"Bruteforce %10lu sectors remaining (test %u), ",
        (unsigned long)((offset-partition->part_offset)/sector_size),
	pass);
  }
  else
  {
    wprintw(window,"Pass %u - Reading sector %10llu/%llu, ",
	pass,
	(unsigned long long)((offset-partition->part_offset)/sector_size),
	(unsigned long long)(partition->part_size/sector_size));
  }
  if(params->status==STATUS_FIND_OFFSET)
    wprintw(window,"%u/10 headers found\n", params->file_nbr);
  else
    wprintw(window,"%u files found\n", params->file_nbr);
  wmove(window,11,0);
  wclrtoeol(window);
  if(current_time > params->real_start_time)
  {
    const time_t elapsed_time=current_time - params->real_start_time;
    wprintw(window,"Elapsed time %uh%02um%02us",
	(unsigned)(elapsed_time/60/60),
	(unsigned)(elapsed_time/60%60),
	(unsigned)(elapsed_time%60));
    if(offset > partition->part_offset && params->status!=STATUS_EXT2_ON_BF && params->status!=STATUS_EXT2_OFF_BF)
    {
      const time_t eta=(partition->part_offset+partition->part_size-1-offset)*elapsed_time/(offset-partition->part_offset);
      wprintw(window," - Estimated time to completion %uh%02um%02u\n",
	  (unsigned)(eta/3600),
	  (unsigned)((eta/60)%60),
	  (unsigned)(eta%60));
    }
  }
  photorec_info(window, params->file_stats);
  wrefresh(window);
  return(check_enter_key_or_s(window)==0?PSTATUS_OK:PSTATUS_STOP);
}
Пример #3
0
static int fat_unformat_aux(struct ph_param *params, const struct ph_options *options, const uint64_t start_offset, alloc_data_t *list_search_space)
{
  int ind_stop=0;
  uint64_t offset;
  uint64_t offset_end;
  unsigned char *buffer_start;
  unsigned char *buffer;
  time_t start_time;
  time_t previous_time;
  const unsigned int blocksize=params->blocksize;
  const unsigned int read_size=(blocksize>65536?blocksize:65536);
  alloc_data_t *current_search_space;
  file_recovery_t file_recovery;
  disk_t *disk=params->disk;
  const partition_t *partition=params->partition;

  reset_file_recovery(&file_recovery);
  file_recovery.blocksize=blocksize;
  buffer_start=(unsigned char *)MALLOC(READ_SIZE);
  buffer=buffer_start;
  start_time=time(NULL);
  previous_time=start_time;
  current_search_space=td_list_entry(list_search_space->list.prev, alloc_data_t, list);
  if(current_search_space==list_search_space)
  {
    free(buffer_start);
    return 0;
  }
  offset_end=current_search_space->end;
  current_search_space=td_list_entry(list_search_space->list.next, alloc_data_t, list);
  offset=set_search_start(params, &current_search_space, list_search_space);
  if(options->verbose>0)
    info_list_search_space(list_search_space, current_search_space, disk->sector_size, 0, options->verbose);
  disk->pread(disk, buffer, READ_SIZE, offset);
  for(;offset < offset_end; offset+=blocksize)
  {
    if(memcmp(buffer,         ".          ", 8+3)==0 &&
	memcmp(&buffer[0x20], "..         ", 8+3)==0)
    {
      file_data_t *dir_list;
      dir_list=dir_fat_aux(buffer,read_size,0,0);
      if(dir_list!=NULL)
      {
	const file_data_t *current_file;
	log_info("Sector %llu\n", (long long unsigned)offset/disk->sector_size);
	dir_aff_log(NULL, dir_list);
	del_search_space(list_search_space, offset, offset + blocksize -1);
	current_file=dir_list;
	while(current_file!=NULL)
	{
	  if(strcmp(current_file->name,".")==0 &&
	      LINUX_S_ISDIR(current_file->stat.st_mode)!=0 &&
	      current_file!=dir_list)
	    current_file=NULL;
	  else if(current_file->stat.st_ino>2 &&
	      LINUX_S_ISREG(current_file->stat.st_mode)!=0)
	  {
	    const uint64_t file_start=start_offset + (uint64_t)(current_file->stat.st_ino - 2) * blocksize;
#ifdef DJGPP
	    const uint64_t file_end=file_start+(current_file->file_size+blocksize-1)/blocksize*blocksize - 1;
#else
	    const uint64_t file_end=file_start+(current_file->stat.st_size+blocksize-1)/blocksize*blocksize - 1;
#endif
	    if(file_end < partition->part_offset + partition->part_size)
	    {
	      if(fat_copy_file(disk, partition, blocksize, start_offset, params->recup_dir, params->dir_num, current_file)==0)
	      {
		params->file_nbr++;
		del_search_space(list_search_space, file_start, file_end);
	      }
	      current_file=current_file->next;
	    }
	    else
	      current_file=NULL;
	  }
	  else
	    current_file=current_file->next;
	}
	delete_list_file(dir_list);
      }
    }
    buffer+=blocksize;
    if(buffer+read_size>buffer_start+READ_SIZE)
    {
      buffer=buffer_start;
      if(options->verbose>1)
      {
        log_verbose("Reading sector %10llu/%llu\n",
	    (unsigned long long)((offset-partition->part_offset)/disk->sector_size),
	    (unsigned long long)((partition->part_size-1)/disk->sector_size));
      }
      if(disk->pread(disk, buffer, READ_SIZE, offset) != READ_SIZE)
      {
#ifdef HAVE_NCURSES
	wmove(stdscr,11,0);
	wclrtoeol(stdscr);
	wprintw(stdscr,"Error reading sector %10lu\n",
	    (unsigned long)((offset-partition->part_offset)/disk->sector_size));
#endif
      }
#ifdef HAVE_NCURSES
      {
        time_t current_time;
        current_time=time(NULL);
        if(current_time>previous_time)
        {
	  const time_t elapsed_time=current_time - params->real_start_time;
          previous_time=current_time;
	  wmove(stdscr,9,0);
	  wclrtoeol(stdscr);
	  log_info("Reading sector %10llu/%llu, %u files found\n",
	      (unsigned long long)((offset-partition->part_offset)/disk->sector_size),
	      (unsigned long long)(partition->part_size/disk->sector_size), params->file_nbr);
	  wprintw(stdscr,"Reading sector %10llu/%llu, %u files found\n",
	      (unsigned long long)((offset-partition->part_offset)/disk->sector_size),
	      (unsigned long long)(partition->part_size/disk->sector_size), params->file_nbr);
	  wmove(stdscr,10,0);
	  wclrtoeol(stdscr);
	  wprintw(stdscr,"Elapsed time %uh%02um%02us",
	      (unsigned)(elapsed_time/60/60),
	      (unsigned)(elapsed_time/60%60),
	      (unsigned)(elapsed_time%60));
	  if(offset-partition->part_offset!=0)
	  {
	    wprintw(stdscr," - Estimated time to completion %uh%02um%02u\n",
		(unsigned)((partition->part_offset+partition->part_size-1-offset)*elapsed_time/(offset-partition->part_offset)/3600),
		(unsigned)(((partition->part_offset+partition->part_size-1-offset)*elapsed_time/(offset-partition->part_offset)/60)%60),
		(unsigned)((partition->part_offset+partition->part_size-1-offset)*elapsed_time/(offset-partition->part_offset))%60);
	  }
	  wrefresh(stdscr);
	  if(check_enter_key_or_s(stdscr))
	  {
	    log_info("PhotoRec has been stopped\n");
	    params->offset=offset;
	    offset = offset_end;
	    ind_stop=1;
	  }
	}
      }
#endif
    }
  }
  free(buffer_start);
  return ind_stop;
}
Пример #4
0
list_part_t *search_superblock(disk_t *disk_car, partition_t *partition, const int verbose, const int dump_ind, const int interface)
{
  unsigned char *buffer=(unsigned char *)MALLOC(2*0x200);
  uint64_t hd_offset;
  int nbr_sb=0;
  list_part_t *list_part=NULL;
  int ind_stop=0;
#ifdef HAVE_NCURSES
  unsigned long int old_percent=0;
#endif
  struct ext2_super_block *sb=(struct ext2_super_block *)buffer;
  partition_t *new_partition=partition_new(disk_car->arch);
  log_trace("search_superblock\n");
#ifdef HAVE_NCURSES
  if(interface>0)
  {
    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);
    wmove(stdscr,22,0);
    wattrset(stdscr, A_REVERSE);
    waddstr(stdscr,"  Stop  ");
    wattroff(stdscr, A_REVERSE);
  }
#endif
  for(hd_offset=0;hd_offset<partition->part_size && nbr_sb<10 && ind_stop==0;hd_offset=next_sb(hd_offset))
  {
#ifdef HAVE_NCURSES
    unsigned long int percent;
    percent=hd_offset*100/partition->part_size;
    if(interface>0 && percent!=old_percent)
    {
      wmove(stdscr,9,0);
      wclrtoeol(stdscr);
      wprintw(stdscr,"Search ext2/ext3/ext4 superblock %10lu/%lu %lu%%", (long unsigned)(hd_offset/disk_car->sector_size),
	  (long unsigned)(partition->part_size/disk_car->sector_size),percent);
      wrefresh(stdscr);
      ind_stop|=check_enter_key_or_s(stdscr);
      old_percent=percent;
    }
#endif
    if(disk_car->pread(disk_car, buffer, 1024, partition->part_offset + hd_offset) == 1024)
    {
      /* ext2/ext3/ext4 */
      if(le16(sb->s_magic)==EXT2_SUPER_MAGIC)
      {
	dup_partition_t(new_partition,partition);
	new_partition->part_offset+=hd_offset;
	if(recover_EXT2(disk_car,sb,new_partition,verbose,dump_ind)==0)
	{
	  int insert_error=0;
	  if(hd_offset<=(EXT2_MIN_BLOCK_SIZE<<2))
	    new_partition->part_offset-=hd_offset;
	  if(partition->blocksize==0)
	  {
	    partition->sborg_offset=new_partition->sborg_offset;
	    partition->sb_offset   =new_partition->sb_offset;
	    partition->sb_size     =new_partition->sb_size;
	    partition->blocksize   =new_partition->blocksize;
	  }
	  log_info("Ext2 superblock found at sector %llu (block=%llu, blocksize=%u)\n",
	      (long long unsigned) hd_offset/DEFAULT_SECTOR_SIZE,
	      (long long unsigned) hd_offset>>(EXT2_MIN_BLOCK_LOG_SIZE+le32(sb->s_log_block_size)),
	      EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size));
#ifdef HAVE_NCURSES
	  wmove(stdscr,10+nbr_sb,0);
	  wprintw(stdscr,"Ext2 superblock found at sector %llu (block=%llu, blocksize=%u)        \n",
	      (long long unsigned) hd_offset/DEFAULT_SECTOR_SIZE,
	      (long long unsigned) hd_offset>>(EXT2_MIN_BLOCK_LOG_SIZE+le32(sb->s_log_block_size)),
	      EXT2_MIN_BLOCK_SIZE<<le32(sb->s_log_block_size));
#endif
	  list_part=insert_new_partition(list_part, new_partition, 1, &insert_error);
	  new_partition=partition_new(disk_car->arch);
	  nbr_sb++;
	}
      }
    }
Пример #5
0
int disk_image(disk_t *disk, const partition_t *partition, const char *image_dd)
{
  int ind_stop=0;
  uint64_t nbr_read_error=0;
  uint64_t src_offset=partition->part_offset;
  uint64_t src_offset_old;
  uint64_t dst_offset=0;
  const uint64_t src_offset_end=partition->part_offset+partition->part_size;
  const uint64_t offset_inc=(src_offset_end-src_offset)/10000;
  uint64_t src_offset_next=src_offset;
  struct stat stat_buf;
  unsigned char *buffer=(unsigned char *)MALLOC(READ_SIZE);
  unsigned int readsize=READ_SIZE;
  int disk_dst;
#ifdef HAVE_NCURSES
  WINDOW *window;
#endif
  if((disk_dst=open(image_dd, O_CREAT|O_LARGEFILE|O_RDWR|O_BINARY, 0644)) < 0)
  {
    log_error("Can't create file %s.\n",image_dd);
    display_message("Can't create file!\n");
    free(buffer);
    return -1;
  }
  if(fstat(disk_dst, &stat_buf)==0)
  {
    int res=1;
#ifdef HAVE_NCURSES
    if(stat_buf.st_size > 0)
      res=ask_confirmation("Append to existing file ? (Y/N)");
#endif
    if(res>0)
    {
      dst_offset=stat_buf.st_size;
      src_offset+=dst_offset;
    }
  }
  src_offset_old=src_offset;
#ifdef HAVE_NCURSES
  window=newwin(LINES, COLS, 0, 0);	/* full screen */
  aff_copy(window);
  wmove(window,5,0);
  wprintw(window,"%s\n",disk->description_short(disk));
  wmove(window,6,0);
  aff_part(window,AFF_PART_ORDER|AFF_PART_STATUS,disk,partition);
  wmove(window,10,0);
  waddstr(window, "Disk images are mainly used ");
  wmove(window,11,0);
  waddstr(window, "- for forensics purpose");
  wmove(window,12,0);
  waddstr(window, "- or to deal with media with bad sectors");
#ifdef WIN32
  wmove(window,14,0);
  waddstr(window, "To use TestDisk or PhotoRec with this disk image, go in command line and run");
  wmove(window,15,0);
  waddstr(window, "   testdisk_win.exe image.dd");
  wmove(window,16,0);
  waddstr(window, "or photorec_win.exe image.dd");
#else
  wmove(window,14,0);
  waddstr(window, "To use TestDisk or PhotoRec with this disk image, start a Terminal and run");
  wmove(window,15,0);
  waddstr(window, "   testdisk image.dd");
  wmove(window,16,0);
  waddstr(window, "or photorec image.dd");
#endif
  wmove(window,22,0);
  wattrset(window, A_REVERSE);
  waddstr(window,"  Stop  ");
  wattroff(window, A_REVERSE);
#endif
  while(ind_stop==0 && src_offset < src_offset_end)
  {
    ssize_t pread_res;
    int update=0;
    if(src_offset_end-src_offset < readsize)
      readsize=src_offset_end-src_offset;
    pread_res=disk->pread(disk, buffer, readsize, src_offset);
    if(pread_res > 0)
    {
#if defined(HAVE_PWRITE)
      if(pwrite(disk_dst, buffer, pread_res, dst_offset)<0)
      {
	ind_stop=2;
      }
#else
      if(lseek(disk_dst, dst_offset, SEEK_SET)<0)
      {
	ind_stop=2;
      }
      if(write(disk_dst, buffer, pread_res) != pread_res)
      {
	ind_stop=2;
      }
#endif
      if(src_offset_old + SKIP_SIZE==src_offset)
      {
	disk_image_backward(disk_dst, disk, src_offset_old, src_offset, dst_offset);
      }
    }
    src_offset_old=src_offset;
    if((unsigned)pread_res == readsize)
    {
      src_offset+=readsize;
      dst_offset+=readsize;
      readsize=READ_SIZE;
    }
    else
    {
      update=1;
      nbr_read_error++;
      readsize=disk->sector_size;
      src_offset+=SKIP_SIZE;
      dst_offset+=SKIP_SIZE;
    }
    if(src_offset>src_offset_next)
    {
      update=1;
      src_offset_next=src_offset+offset_inc;
    }
    if(update)
    {
#ifdef HAVE_NCURSES
      unsigned int i;
      const float percent=(src_offset-partition->part_offset)*100.00/partition->part_size;
      wmove(window,7,0);
      wprintw(window,"%3.2f %% ", percent);
      for(i=0;i<percent*3/5;i++)
	wprintw(window,"=");
      wprintw(window,">");
      wrefresh(window);
      ind_stop=check_enter_key_or_s(window);
#endif
    }
  }
  close(disk_dst);
#ifdef HAVE_NCURSES
  delwin(window);
  (void) clearok(stdscr, TRUE);
#ifdef HAVE_TOUCHWIN
  touchwin(stdscr);
#endif
#endif
  if(ind_stop==2)
  {
    display_message("No space left for the file image.\n");
    free(buffer);
    return -2;
  }
  if(ind_stop)
  {
    if(nbr_read_error==0)
      display_message("Incomplete image created.\n");
    else
      display_message("Incomplete image created: read errors have occured.\n");
    free(buffer);
    return 0;
  }
  if(nbr_read_error==0)
    display_message("Image created successfully.\n");
  else
    display_message("Image created successfully but read errors have occured.\n");
  free(buffer);
  return 0;
}
Пример #6
0
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;
}