/* File: fat_cluster.c Copyright (C) 1998-2009 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 #include #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #include "types.h" #include "common.h" #include "intrf.h" #include "intrfn.h" #include "log.h" #include "fat_cluster.h" #include "fat.h" #include "fat_common.h" /* 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, const partition_t *partition, const int verbose, const int dump_ind, 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 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*3/2/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; offsetpart_size && !ind_stop && nbr_subdir<10; offset+=disk_car->sector_size) { #ifdef HAVE_NCURSES if((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(buffer[0]=='.' && is_fat_directory(buffer)) { const unsigned long int cluster=fat_get_cluster_from_entry((const struct msdos_dir_entry *)buffer); 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); } int find_sectors_per_cluster_aux(const sector_cluster_t *sector_cluster, const unsigned int nbr_sector_cluster,unsigned int *sectors_per_cluster, uint64_t *offset, const int verbose, const unsigned long int part_size_in_sectors, const upart_type_t upart_type) { cluster_offset_t *cluster_offset; unsigned int i,j; unsigned int nbr_sol=0; if(nbr_sector_cluster<2) return 0; cluster_offset=(cluster_offset_t *)MALLOC(nbr_sector_cluster*nbr_sector_cluster*sizeof(cluster_offset_t)); log_info("find_sectors_per_cluster_aux\n"); for(i=0;i sector_cluster[i].cluster) { unsigned int sectors_per_cluster_tmp=(sector_cluster[j].sector-sector_cluster[i].sector)/(sector_cluster[j].cluster-sector_cluster[i].cluster); switch(sectors_per_cluster_tmp) { case 1: case 2: case 4: case 8: case 16: case 32: case 64: case 128: if(sector_cluster[i].sector > (uint64_t)(sector_cluster[i].cluster-2) * sectors_per_cluster_tmp) { unsigned int sol_cur; unsigned int found=0; uint64_t offset_tmp=sector_cluster[i].sector-(uint64_t)(sector_cluster[i].cluster-2)*sectors_per_cluster_tmp; for(sol_cur=0;sol_cur0) { log_verbose("sectors_per_cluster=%u offset=%lu nbr=%u ", cluster_offset[i].sectors_per_cluster, cluster_offset[i].offset, cluster_offset[i].nbr); switch(upart_type_new) { case UP_FAT12: log_info("FAT : 12\n"); break; case UP_FAT16: log_info("FAT : 16\n"); break; case UP_FAT32: log_info("FAT : 32\n"); break; default: /* No compiler warning */ break; } } if((upart_type==UP_UNK || upart_type==upart_type_new) && cluster_offset[i].nbr>nbr_max) { nbr_max=cluster_offset[i].nbr; *sectors_per_cluster=cluster_offset[i].sectors_per_cluster; *offset=cluster_offset[i].offset; } } free(cluster_offset); if(nbr_max==0) return 0; log_info("Selected: sectors_per_cluster=%u, cluster 2 at sector %lu, nbr=%u\n", *sectors_per_cluster, (long unsigned int)(*offset), nbr_max); return 1; } } upart_type_t no_of_cluster2part_type(const unsigned long int no_of_cluster) { if(no_of_cluster<65525) { if(no_of_cluster<4085) return UP_FAT12; else return UP_FAT16; } return UP_FAT32; }