/*
File: fnctdsk.c
Copyright (C) 1998-2005 Christophe GRENIER <grenier@cgsecurity.org>
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 <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#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_offset<next->part->part_offset) ||
(new_element->part->part_offset==next->part->part_offset &&
((new_element->part->part_size<next->part->part_size) ||
(new_element->part->part_size==next->part->part_size && (dont_free_part!=2 || new_element->part->boot_sector<next->part->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;
}
syntax highlighted by Code2HTML, v. 0.9.1