testdisk/src/partmac.c
2020-08-08 12:26:37 +02:00

465 lines
14 KiB
C

/*
File: partmac.c
Copyright (C) 1998-2008 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 <ctype.h> /* tolower */
#include <assert.h>
#include "types.h"
#include "common.h"
#include "fnctdsk.h"
#include "lang.h"
#include "intrf.h"
#include "analyse.h"
#include "chgtype.h"
#include "partmac.h"
#include "savehdr.h"
#include "fat.h"
#include "hfs.h"
#include "hfsp.h"
#include "log.h"
/*@
@ requires \valid(disk_car);
@ requires \valid(partition);
@*/
static int check_part_mac(disk_t *disk_car, const int verbose,partition_t *partition,const int saveheader);
/*@
@ requires \valid(disk_car);
@*/
static list_part_t *read_part_mac(disk_t *disk_car, const int verbose, const int saveheader);
/*@
@ requires \valid(disk_car);
@ requires list_part == \null || \valid(list_part);
@*/
static int write_part_mac(disk_t *disk_car, const list_part_t *list_part, const int ro , const int verbose);
/*@
@ requires \valid(disk_car);
@ requires list_part == \null || \valid(list_part);
@ requires separation: \separated(disk_car, list_part);
@ assigns \nothing;
@*/
static list_part_t *init_part_order_mac(const disk_t *disk_car, list_part_t *list_part);
/*@
@ requires \valid_read(disk_car);
@ requires \valid(partition);
@ requires separation: \separated(disk_car, partition);
@ assigns partition->status;
@*/
static void set_next_status_mac(const disk_t *disk_car, partition_t *partition);
/*@
@ requires \valid(partition);
@ assigns partition->part_type_mac;
@*/
static int set_part_type_mac(partition_t *partition, unsigned int part_type_mac);
/*@
@ requires \valid(partition);
@ assigns \nothing;
@*/
static int is_part_known_mac(const partition_t *partition);
/*@
@ requires \valid_read(disk_car);
@ requires list_part == \null || \valid(list_part);
@*/
static void init_structure_mac(const disk_t *disk_car,list_part_t *list_part, const int verbose);
/*@
@ requires \valid_read(partition);
@ assigns \nothing;
@*/
static const char *get_partition_typename_mac(const partition_t *partition);
/*@
@ assigns \nothing;
@*/
static const char *get_partition_typename_mac_aux(const unsigned int part_type_mac);
/*@
@ requires \valid_read(partition);
@ assigns \nothing;
@*/
static unsigned int get_part_type_mac(const partition_t *partition);
static const struct systypes mac_sys_types[] = {
{ PMAC_DRIVER43, "Driver43" },
{ PMAC_DRIVERATA, "Driver_ATA" },
{ PMAC_DRIVERIO, "Driver_IOKit" },
{ PMAC_FREE, "Free" },
{ PMAC_FWDRIVER, "FWDriver" },
{ PMAC_SWAP, "Swap" },
{ PMAC_LINUX, "Linux" },
{ PMAC_BEOS, "BeFS" },
{ PMAC_HFS, "HFS" },
{ PMAC_MAP, "partition_map" },
{ PMAC_PATCHES, "Patches" },
{ PMAC_UNK, "Unknown" },
{ PMAC_NewWorld, "NewWorld" },
{ PMAC_DRIVER, "Driver" },
{ PMAC_MFS, "MFS" },
{ PMAC_PRODOS, "ProDOS" },
{ PMAC_FAT32, "DOS_FAT_32" },
{ PMAC_UNK, NULL }
};
arch_fnct_t arch_mac=
{
.part_name="Mac",
.part_name_option="partition_mac",
.msg_part_type=" P=Primary D=Deleted",
.read_part=&read_part_mac,
.write_part=&write_part_mac,
.init_part_order=&init_part_order_mac,
.get_geometry_from_mbr=NULL,
.check_part=&check_part_mac,
.write_MBR_code=NULL,
.set_prev_status=&set_next_status_mac,
.set_next_status=&set_next_status_mac,
.test_structure=&test_structure_mac,
.get_part_type=&get_part_type_mac,
.set_part_type=&set_part_type_mac,
.init_structure=&init_structure_mac,
.erase_list_part=NULL,
.get_partition_typename=&get_partition_typename_mac,
.is_part_known=&is_part_known_mac
};
static unsigned int get_part_type_mac(const partition_t *partition)
{
return partition->part_type_mac;
}
static list_part_t *read_part_mac(disk_t *disk_car, const int verbose, const int saveheader)
{
unsigned char buffer[DEFAULT_SECTOR_SIZE];
list_part_t *new_list_part=NULL;
unsigned int i;
unsigned int limit=1;
screen_buffer_reset();
if(disk_car->pread(disk_car, &buffer, sizeof(buffer), 0) != sizeof(buffer))
return NULL;
{
mac_Block0 *maclabel=(mac_Block0*)&buffer;
if (be16(maclabel->sbSig) != BLOCK0_SIGNATURE)
{
screen_buffer_add("Bad MAC partition, invalid block0 signature\n");
/* continue, even if the first sector have been overwritten by an Intel
partition, the following sectors may be intact */
}
}
for(i=1;i<=limit;i++)
{
mac_DPME *dpme=(mac_DPME *)buffer;
if(disk_car->pread(disk_car, &buffer, sizeof(buffer), (uint64_t)i * PBLOCK_SIZE) != sizeof(buffer))
return new_list_part;
if(be16(dpme->dpme_signature) != DPME_SIGNATURE)
{
screen_buffer_add("read_part_mac: bad DPME signature\n");
return new_list_part;
}
else
{
int insert_error=0;
partition_t *new_partition=partition_new(&arch_mac);
new_partition->order=i;
if (strcmp(dpme->dpme_type, "Apple_UNIX_SVR2")==0)
{
if (!strcmp(dpme->dpme_name, "Swap") || !strcmp(dpme->dpme_name, "swap"))
new_partition->part_type_mac=PMAC_SWAP;
else
new_partition->part_type_mac=PMAC_LINUX;
}
else if (strcmp(dpme->dpme_type, "Apple_Bootstrap")==0)
new_partition->part_type_mac=PMAC_NewWorld;
else if (strcmp(dpme->dpme_type, "Apple_Scratch")==0)
new_partition->part_type_mac=PMAC_SWAP;
else if(strcmp(dpme->dpme_type,"Apple_Driver")==0)
new_partition->part_type_mac=PMAC_DRIVER;
else if(strcmp(dpme->dpme_type,"Apple_Driver43")==0)
new_partition->part_type_mac=PMAC_DRIVER43;
else if(strcmp(dpme->dpme_type,"Apple_Driver_ATA")==0)
new_partition->part_type_mac=PMAC_DRIVERATA;
else if(strcmp(dpme->dpme_type,"Apple_Driver_IOKit")==0)
new_partition->part_type_mac=PMAC_DRIVERIO;
else if(strcmp(dpme->dpme_type,"Apple_Free")==0)
new_partition->part_type_mac=PMAC_FREE;
else if(strcmp(dpme->dpme_type,"Apple_FWDriver")==0)
new_partition->part_type_mac=PMAC_FWDRIVER;
else if(strcmp(dpme->dpme_type,"Apple_partition_map")==0)
new_partition->part_type_mac=PMAC_MAP;
else if(strcmp(dpme->dpme_type,"Apple_Patches")==0)
new_partition->part_type_mac=PMAC_PATCHES;
else if(strcmp(dpme->dpme_type,"Apple_HFS")==0)
new_partition->part_type_mac=PMAC_HFS;
else if(strcmp(dpme->dpme_type,"Apple_MFS")==0)
new_partition->part_type_mac=PMAC_MFS;
else if(strcmp(dpme->dpme_type,"Apple_PRODOS")==0)
new_partition->part_type_mac=PMAC_PRODOS;
else if(strcmp(dpme->dpme_type,"Be_BFS")==0)
new_partition->part_type_mac=PMAC_BEOS;
else if(strcmp(dpme->dpme_type,"DOS_FAT_32")==0)
new_partition->part_type_mac=PMAC_FAT32;
else
{
new_partition->part_type_mac=PMAC_UNK;
log_error("%s\n",dpme->dpme_type);
}
new_partition->part_offset=(uint64_t)be32(dpme->dpme_pblock_start)*PBLOCK_SIZE;
new_partition->part_size=(uint64_t)be32(dpme->dpme_pblocks)*PBLOCK_SIZE;
new_partition->status=STATUS_PRIM;
check_part_mac(disk_car,verbose,new_partition,saveheader);
aff_part_buffer(AFF_PART_ORDER|AFF_PART_STATUS,disk_car,new_partition);
new_list_part=insert_new_partition(new_list_part, new_partition, 0, &insert_error);
if(insert_error>0)
free(new_partition);
if(i==1)
{
limit=be32(dpme->dpme_map_entries);
}
}
}
return new_list_part;
}
static int write_part_mac(disk_t *disk_car, const list_part_t *list_part, const int ro, const int verbose)
{
/* TODO: Implement it */
if(ro==0)
return -1;
return 0;
}
static list_part_t *init_part_order_mac(const disk_t *disk_car, list_part_t *list_part)
{
return list_part;
}
list_part_t *add_partition_mac_cli(disk_t *disk_car,list_part_t *list_part, char **current_cmd)
{
partition_t *new_partition=partition_new(&arch_mac);
assert(current_cmd!=NULL);
new_partition->part_offset=disk_car->sector_size;
new_partition->part_size=disk_car->disk_size-disk_car->sector_size;
while(1)
{
skip_comma_in_command(current_cmd);
if(check_command(current_cmd,"s,",2)==0)
{
uint64_t part_offset;
part_offset=new_partition->part_offset;
new_partition->part_offset=(uint64_t)ask_number_cli(
current_cmd,
new_partition->part_offset/disk_car->sector_size,
4096/disk_car->sector_size,
(disk_car->disk_size-1)/disk_car->sector_size,
"Enter the starting sector ") *
(uint64_t)disk_car->sector_size;
new_partition->part_size=new_partition->part_size + part_offset - new_partition->part_offset;
}
else if(check_command(current_cmd,"S,",2)==0)
{
new_partition->part_size=(uint64_t)ask_number_cli(
current_cmd,
(new_partition->part_offset+new_partition->part_size-1)/disk_car->sector_size,
new_partition->part_offset/disk_car->sector_size,
(disk_car->disk_size-1)/disk_car->sector_size,
"Enter the ending sector ") *
(uint64_t)disk_car->sector_size +
disk_car->sector_size - new_partition->part_offset;
}
else if(check_command(current_cmd,"T,",2)==0)
{
change_part_type_cli(disk_car,new_partition,current_cmd);
}
else if(new_partition->part_size>0 && new_partition->part_type_mac>0)
{
int insert_error=0;
list_part_t *new_list_part=insert_new_partition(list_part, new_partition, 0, &insert_error);
if(insert_error>0)
{
free(new_partition);
return new_list_part;
}
new_partition->status=STATUS_PRIM;
if(test_structure_mac(list_part)!=0)
new_partition->status=STATUS_DELETED;
return new_list_part;
}
else
{
free(new_partition);
return list_part;
}
}
}
static void set_next_status_mac(const disk_t *disk_car, partition_t *partition)
{
if(partition->status==STATUS_DELETED)
partition->status=STATUS_PRIM;
else
partition->status=STATUS_DELETED;
}
int test_structure_mac(const list_part_t *list_part)
{ /* Return 1 if bad*/
list_part_t *new_list_part;
int res;
new_list_part=gen_sorted_partition_list(list_part);
res=is_part_overlapping(new_list_part);
part_free_list_only(new_list_part);
return res;
}
static int set_part_type_mac(partition_t *partition, unsigned int part_type_mac)
{
if(part_type_mac>0 && part_type_mac <= 255)
{
partition->part_type_mac=part_type_mac;
return 0;
}
return 1;
}
static int is_part_known_mac(const partition_t *partition)
{
return (partition->part_type_mac!=PMAC_UNK);
}
static void init_structure_mac(const disk_t *disk_car,list_part_t *list_part, const int verbose)
{
list_part_t *element;
list_part_t *new_list_part=NULL;
/* Create new list */
for(element=list_part;element!=NULL;element=element->next)
element->to_be_removed=0;
for(element=list_part;element!=NULL;element=element->next)
{
list_part_t *element2;
for(element2=element->next;element2!=NULL;element2=element2->next)
{
if(element->part->part_offset+element->part->part_size-1 >= element2->part->part_offset)
{
element->to_be_removed=1;
element2->to_be_removed=1;
}
}
if(element->to_be_removed==0)
{
int insert_error=0;
new_list_part=insert_new_partition(new_list_part, element->part, 0, &insert_error);
}
}
for(element=new_list_part;element!=NULL;element=element->next)
element->part->status=STATUS_PRIM;
if(test_structure_mac(new_list_part))
{
for(element=new_list_part;element!=NULL;element=element->next)
element->part->status=STATUS_DELETED;
}
part_free_list_only(new_list_part);
}
static int check_part_mac(disk_t *disk_car,const int verbose,partition_t *partition, const int saveheader)
{
int ret=0;
switch(partition->part_type_mac)
{
case PMAC_DRIVER43:
case PMAC_DRIVERATA:
case PMAC_DRIVERIO:
case PMAC_FREE:
case PMAC_FWDRIVER:
case PMAC_SWAP:
case PMAC_MAP:
case PMAC_PATCHES:
case PMAC_UNK:
case PMAC_NewWorld:
case PMAC_DRIVER:
case PMAC_MFS:
case PMAC_BEOS:
case PMAC_PRODOS:
break;
case PMAC_LINUX:
ret=check_linux(disk_car, partition, verbose);
if(ret!=0)
screen_buffer_add("No ext2, JFS, Reiser, cramfs or XFS marker\n");
break;
case PMAC_HFS:
ret=check_HFSP(disk_car,partition,verbose);
if(ret!=0)
{
ret=check_HFS(disk_car,partition,verbose);
}
break;
case PMAC_FAT32:
ret=check_FAT(disk_car, partition, verbose);
break;
default:
if(verbose>0)
{
log_info("check_part_mac %u type %02X: no test\n",partition->order,partition->part_type_mac);
}
break;
}
if(ret!=0)
{
log_error("check_part_mac failed for partition type %02X\n", partition->part_type_mac);
aff_part_buffer(AFF_PART_ORDER|AFF_PART_STATUS,disk_car,partition);
if(saveheader>0)
{
save_header(disk_car,partition,verbose);
}
}
return ret;
}
static const char *get_partition_typename_mac_aux(const unsigned int part_type_mac)
{
int i;
/*@ loop assigns i; */
for (i=0; mac_sys_types[i].name!=NULL; i++)
if (mac_sys_types[i].part_type == part_type_mac)
return mac_sys_types[i].name;
return NULL;
}
static const char *get_partition_typename_mac(const partition_t *partition)
{
return get_partition_typename_mac_aux(partition->part_type_mac);
}