/* fat_unformat()
 * @param struct ph_param *params
 * @param const struct ph_options *options
 * @param alloc_data_t *list_search_space
 *
 * @returns:
 * 0: Completed or not possible
 * 1: Stop by user request
 *    params->offset is set
 */
int fat_unformat(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space)
{
  unsigned int sectors_per_cluster=0;
  uint64_t start_data=0;
  params->blocksize=0;
  if(pfind_sectors_per_cluster(params->disk, params->partition, options->verbose, &sectors_per_cluster, &start_data, list_search_space)==0)
  {
    display_message("Can't find FAT cluster size\n");
    return 0;
  }
  if(start_data <= params->partition->part_offset)
  {
    display_message("FAT filesystem was beginning before the actual partition.");
    return 0;
  }
  start_data *= params->disk->sector_size;
  del_search_space(list_search_space, params->partition->part_offset, start_data - 1);
  {
    uint64_t offset=start_data;
    params->blocksize=sectors_per_cluster * params->disk->sector_size;
#ifdef HAVE_NCURSES
    if(options->expert>0)
      params->blocksize=menu_choose_blocksize(params->blocksize, params->disk->sector_size, &offset);
#endif
    update_blocksize(params->blocksize, list_search_space, offset);
  }
  /* start_data is relative to the disk */
  return fat_unformat_aux(params, options, start_data, list_search_space);
}
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;
}
Exemple #3
0
unsigned int exfat_remove_used_space(disk_t *disk, const partition_t *partition, alloc_data_t *list_search_space)
{
  struct exfat_super_block *exfat_header;
  unsigned int cluster_shift;
  /* Load boot sector */
  exfat_header=(struct exfat_super_block *)MALLOC(0x200);
  if(disk->pread(disk, exfat_header, 0x200, partition->part_offset) != 0x200)
  {
    log_error("Can't read exFAT boot sector.\n");
    free(exfat_header);
    return 0;
  }
  cluster_shift=exfat_header->block_per_clus_bits + exfat_header->blocksize_bits;
  /* Load bitmap information */
  {
    const struct exfat_alloc_bitmap_entry *bitmap;
    const uint64_t start=partition->part_offset +
      exfat_cluster_to_offset(exfat_header, le32(exfat_header->rootdir_clusnr));
    unsigned char *buffer_rootdir=(unsigned char *)MALLOC(1<<cluster_shift);
    unsigned char *buffer;
    unsigned int i;
    unsigned int cluster_bitmap;
    const uint64_t start_exfat1=(uint64_t)le32(exfat_header->fat_blocknr) << exfat_header->blocksize_bits;
    uint64_t start_free=0;
    uint64_t end_free=0;
    if(disk->pread(disk, buffer_rootdir, 1 << cluster_shift, start) != (1<<cluster_shift))
    {
      log_error("exFAT: Can't root directory cluster.\n");
      free(buffer_rootdir);
      free(exfat_header);
      return 0; 
    }
    bitmap=exfat_get_bitmap(buffer_rootdir, 1<<cluster_shift);
    if(bitmap==NULL)
    {
      log_error("exFAT: Can't find bitmap.\n");
      free(buffer_rootdir);
      free(exfat_header);
      return 0; 
    }
    cluster_bitmap=le32(bitmap->first_cluster);
    log_trace("exfat_remove_used_space\n");
    buffer=(unsigned char *)MALLOC(1<<cluster_shift);
    for(i=2; i<le32(exfat_header->total_clusters)+2; i++)
    {
      const unsigned int offset_o=(i-2)%(8<<cluster_shift);
      if(offset_o==0)
      {
	exfat_read_cluster(disk, partition, exfat_header, buffer, cluster_bitmap);
	cluster_bitmap=get_next_cluster(disk, partition, UP_FAT32, start_exfat1, cluster_bitmap);
      }
      if(((buffer[offset_o/8]>>(offset_o%8))&1) != 0)
      {
	/* Not free */
	if(end_free+1==partition->part_offset + exfat_cluster_to_offset(exfat_header, i))
	  end_free+=(1<<cluster_shift);
	else
	{
	  if(start_free != end_free)
	    del_search_space(list_search_space, start_free, end_free);
	  start_free=partition->part_offset + exfat_cluster_to_offset(exfat_header, i);
	  end_free=start_free + (1<<cluster_shift) - 1;
	}
      }
    }
    free(buffer);
    if(start_free != end_free)
      del_search_space(list_search_space, start_free, end_free);
    free(buffer_rootdir);
    free(exfat_header);
  }
  return (1<<cluster_shift);
}