/* File: fnctdsk.c Copyright (C) 1998-2005 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_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "types.h" #include "common.h" #include "fnctdsk.h" #include "lang.h" #include "testdisk.h" #include "analyse.h" #include "log.h" static unsigned int get_geometry_from_list_part_aux(const disk_t *disk_car, const list_part_t *list_part, const int debug); unsigned long int C_H_S2LBA(const disk_t *disk_car,const unsigned int C, const unsigned int H, const unsigned int S) { return ((unsigned long int)C*(disk_car->CHS.head+1)+H)*disk_car->CHS.sector+S-1; } uint64_t CHS2offset(const disk_t *disk_car,const CHS_t*CHS) { return (((uint64_t)CHS->cylinder*(disk_car->CHS.head+1)+CHS->head)*disk_car->CHS.sector+CHS->sector-1)*disk_car->sector_size; } uint64_t C_H_S2offset(const disk_t *disk_car,const unsigned int C, const unsigned int H, const unsigned int S) { return (((uint64_t)C*(disk_car->CHS.head+1)+H)*disk_car->CHS.sector+S-1)*disk_car->sector_size; } unsigned int offset2sector(const disk_t *disk_car, const uint64_t offset) { return ((offset/disk_car->sector_size)%disk_car->CHS.sector)+1; } unsigned int offset2head(const disk_t *disk_car, const uint64_t offset) { return ((offset/disk_car->sector_size)/disk_car->CHS.sector)%(disk_car->CHS.head+1); } unsigned int offset2cylinder(const disk_t *disk_car, const uint64_t offset) { return ((offset/disk_car->sector_size)/disk_car->CHS.sector)/(disk_car->CHS.head+1); } void offset2CHS(const disk_t *disk_car,const uint64_t offset, CHS_t*CHS) { uint64_t pos=offset/disk_car->sector_size; CHS->sector=(pos%disk_car->CHS.sector)+1; pos/=disk_car->CHS.sector; CHS->head=pos%(disk_car->CHS.head+1); CHS->cylinder=pos/(disk_car->CHS.head+1); } void dup_CHS(CHS_t * CHS_dest, const CHS_t * CHS_source) { CHS_dest->cylinder=CHS_source->cylinder; CHS_dest->head=CHS_source->head; CHS_dest->sector=CHS_source->sector; } void dup_partition_t(partition_t *dest, const partition_t *src) { dest->part_offset=src->part_offset; dest->part_size=src->part_size; dest->boot_sector=src->boot_sector; dest->blocksize=src->blocksize; dest->part_type_i386=src->part_type_i386; dest->part_type_sun=src->part_type_sun; dest->part_type_mac=src->part_type_mac; dest->part_type_xbox=src->part_type_xbox; dest->upart_type=src->upart_type; dest->status=src->status; dest->order=src->order; dest->errcode=src->errcode; strncpy(dest->info,src->info,sizeof(dest->info)); strncpy(dest->name,src->name,sizeof(dest->name)); dest->arch=src->arch; } list_disk_t *insert_new_disk(list_disk_t *list_disk, disk_t *disk_car) { if(disk_car==NULL) return list_disk; { list_disk_t *cur; list_disk_t *prev=NULL; list_disk_t *new_disk; /* Add it at the end if it doesn't already exist */ for(cur=list_disk;cur!=NULL;cur=cur->next) { if(cur->disk->device!=NULL && disk_car->device!=NULL) { if(strcmp(cur->disk->device,disk_car->device)==0) { if(disk_car->clean!=NULL) disk_car->clean(disk_car); free(disk_car->device); free(disk_car); return list_disk; } } prev=cur; } new_disk=(list_disk_t *)MALLOC(sizeof(*new_disk)); new_disk->disk=disk_car; if(prev!=NULL) { prev->next=new_disk; } new_disk->prev=prev; new_disk->next=NULL; return (list_disk!=NULL?list_disk:new_disk); } } list_part_t *insert_new_partition(list_part_t *list_part, partition_t *part) { list_part_t *new_list_part; #ifdef DEBUG check_list_part(list_part); #endif new_list_part=insert_new_partition_aux(list_part, element_new(part),0); #ifdef DEBUG check_list_part(new_list_part); #endif return new_list_part; } list_part_t *insert_new_partition_aux(list_part_t *list_part, list_part_t *new_element, const unsigned int dont_free_part) { /*dont_free_part 0 if new_element->part is already known, don't insert it and free it 1 if new_element->part is already known, don't insert it but free it 2 even if new_element->part is already known, insert it */ /* new partition mustn't be used after insert !*/ list_part_t *prev=NULL; list_part_t *next; for(next=list_part;;next=next->next) { /* prev new next */ if((next==NULL)|| (new_element->part->part_offsetpart->part_offset) || (new_element->part->part_offset==next->part->part_offset && ((new_element->part->part_sizepart->part_size) || (new_element->part->part_size==next->part->part_size && (dont_free_part!=2 || new_element->part->boot_sectorpart->boot_sector))))) { if(dont_free_part!=2 && (next!=NULL)&&(next->part->part_offset==new_element->part->part_offset) && (next->part->part_size==new_element->part->part_size) && (next->part->part_type_i386==new_element->part->part_type_i386) && (next->part->part_type_mac==new_element->part->part_type_mac) && (next->part->part_type_sun==new_element->part->part_type_sun) && (next->part->part_type_xbox==new_element->part->part_type_xbox) && (next->part->upart_type==new_element->part->upart_type || new_element->part->upart_type==UP_UNK)) { /*CGR 2004/05/31*/ if(next->part->status==STATUS_DELETED) { next->part->status=new_element->part->status; } if(dont_free_part==0) free(new_element->part); free(new_element); return list_part; } else { /* prev new_element next */ new_element->next=next; new_element->prev=prev; if(next!=NULL) next->prev=new_element; if(prev!=NULL) { prev->next=new_element; return list_part; } return new_element; } } prev=next; } } int delete_list_disk(list_disk_t *list_disk) { list_disk_t *element_disk; int write_used=0; for(element_disk=list_disk;element_disk!=NULL;) { list_disk_t *element_disk_next=element_disk->next; write_used|=element_disk->disk->write_used; if(element_disk->disk->clean!=NULL) element_disk->disk->clean(element_disk->disk); if(element_disk->disk->device!=NULL) free(element_disk->disk->device); free(element_disk->disk); free(element_disk); element_disk=element_disk_next; } return write_used; } int check_list_part(list_part_t *list_part) { list_part_t *prev=NULL; list_part_t *parts; if((list_part!=NULL) && (list_part->prev!=NULL)) { log_critical("\ncheck_list_part error: list_part->prev!=NULL\n"); exit(EXIT_FAILURE); } log_trace("check_list_part\n"); for(parts=list_part;parts!=NULL;parts=parts->next) { log_info("%p %p %p\n",parts->prev, parts, parts->next); if(prev!=parts->prev) { log_critical("\ncheck_list_part error: prev!=parts->prev\n"); exit(EXIT_FAILURE); } prev=parts; } if((prev!=NULL) && (prev->next!=NULL)) { log_critical("\ncheck_list_part error: prev->next!=NULL\n"); exit(EXIT_FAILURE); } return 0; } list_part_t *sorlist_part_t(list_part_t *list_part) { list_part_t *new_list_part=NULL; list_part_t *element; list_part_t *next; #ifdef DEBUG check_list_part(list_part); #endif for(element=list_part;element!=NULL;element=next) { next=element->next; new_list_part=insert_new_partition_aux(new_list_part,element,0); } #ifdef DEBUG check_list_part(new_list_part); #endif return new_list_part; } void delete_list_part(list_part_t *list_part) { list_part_t *element; #ifdef DEBUG check_list_part(list_part); #endif /* Libere la memoire */ element=list_part; while(element!=NULL) { list_part_t *next=element->next; free(element->part); free(element); element=next; } } void partition_reset(partition_t *partition) { /* partition->lba=0; Don't reset lba, used by search_part */ partition->part_size=(uint64_t)0; partition->boot_sector=0; partition->blocksize=0; partition->part_type_i386=P_NO_OS; partition->part_type_sun=PSUN_UNK; partition->part_type_mac=PMAC_UNK; partition->part_type_xbox=PXBOX_UNK; partition->upart_type=UP_UNK; partition->status=STATUS_DELETED; partition->order=NO_ORDER; partition->errcode=BAD_NOERR; partition->name[0]='\0'; partition->info[0]='\0'; partition->arch=NULL; } partition_t *partition_new() { partition_t *partition=(partition_t *)MALLOC(sizeof(*partition)); partition_reset(partition); return partition; } list_part_t *element_new(partition_t *part) { list_part_t *new_element=(list_part_t*)MALLOC(sizeof(*new_element)); new_element->part=part; new_element->prev=new_element->next=NULL; new_element->to_be_removed=0; return new_element; } static unsigned int get_geometry_from_list_part_aux(const disk_t *disk_car, const list_part_t *list_part, const int debug) { const list_part_t *element; unsigned int nbr=0; for(element=list_part;element!=NULL;element=element->next) { CHS_t start; CHS_t end; offset2CHS(disk_car,element->part->part_offset,&start); offset2CHS(disk_car,element->part->part_offset+element->part->part_size-1,&end); if(start.sector==1 && start.head<=1) { nbr++; if(end.head==disk_car->CHS.head) { nbr++; /* Doesn't check if end.sector==disk_car->CHS.sector */ } } } if(nbr>0) { log_info("get_geometry_from_list_part_aux head=%u nbr=%u\n",disk_car->CHS.head+1,nbr); if(debug>1) { for(element=list_part;element!=NULL;element=element->next) { CHS_t start; CHS_t end; offset2CHS(disk_car,element->part->part_offset,&start); offset2CHS(disk_car,element->part->part_offset+element->part->part_size-1,&end); if(start.sector==1 && start.head<=1 && end.head==disk_car->CHS.head) { log_partition(disk_car,element->part); } } } } return nbr; } unsigned int get_geometry_from_list_part(const disk_t *disk_car, const list_part_t *list_part, const int debug) { const unsigned int head_list[]={8,16,32,64,128,240,255,0}; unsigned int nbr_max; unsigned int nbr; unsigned int h_index=0; unsigned int head_max=disk_car->CHS.head; disk_t *new_disk_car=MALLOC(sizeof(*new_disk_car)); memcpy(new_disk_car,disk_car,sizeof(*new_disk_car)); nbr_max=get_geometry_from_list_part_aux(new_disk_car, list_part, debug); for(h_index=0;head_list[h_index]!=0;h_index++) { new_disk_car->CHS.head=head_list[h_index]-1; nbr=get_geometry_from_list_part_aux(new_disk_car, list_part, debug); if(nbr>=nbr_max) { nbr_max=nbr; head_max=new_disk_car->CHS.head; } } free(new_disk_car); return head_max; } const char *size_to_unit(uint64_t disk_size, char *buffer) { if(disk_size<(uint64_t)10*1024) sprintf(buffer,"%u B", (unsigned)disk_size); else if(disk_size<(uint64_t)10*1024*1024) sprintf(buffer,"%u KB / %u KiB", (unsigned)(disk_size/1000), (unsigned)(disk_size/1024)); else if(disk_size<(uint64_t)10*1024*1024*1024) sprintf(buffer,"%u MB / %u MiB", (unsigned)(disk_size/1000/1000), (unsigned)(disk_size/1024/1024)); else if(disk_size<(uint64_t)10*1024*1024*1024*1024) sprintf(buffer,"%u GB / %u GiB", (unsigned)(disk_size/1000/1000/1000), (unsigned)(disk_size/1024/1024/1024)); else sprintf(buffer,"%u TB / %u TiB", (unsigned)(disk_size/1000/1000/1000/1000), (unsigned)(disk_size/1024/1024/1024/1024)); return buffer; }