summaryrefslogtreecommitdiffstats
path: root/src/parti386.c
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2007-10-29 22:38:52 +0100
committerChristophe Grenier <grenier@cgsecurity.org>2007-10-29 22:38:52 +0100
commit9928d99936105b4653d2d1b8ca74dc3ffba5c71e (patch)
tree06aa4f5e9f0055027c6fb54dd47a8414cf2fba32 /src/parti386.c
First version in git
Diffstat (limited to 'src/parti386.c')
-rw-r--r--src/parti386.c1692
1 files changed, 1692 insertions, 0 deletions
diff --git a/src/parti386.c b/src/parti386.c
new file mode 100644
index 0000000..3a7736a
--- /dev/null
+++ b/src/parti386.c
@@ -0,0 +1,1692 @@
+/*
+
+ File: parti386.c
+
+ Copyright (C) 1998-2007 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
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <ctype.h> /* tolower */
+#include "types.h"
+#include "common.h"
+#include "testdisk.h"
+#include "fnctdsk.h"
+#include "lang.h"
+#include "intrf.h"
+#include "intrfn.h"
+#include "chgtype.h"
+#include "savehdr.h"
+#include "bfs.h"
+#include "bsd.h"
+#include "cramfs.h"
+#include "ext2.h"
+#include "fat.h"
+#include "hfs.h"
+#include "hfsp.h"
+#include "jfs_superblock.h"
+#include "jfs.h"
+#include "lvm.h"
+#include "md.h"
+#include "netware.h"
+#include "ntfs.h"
+#include "rfs.h"
+#include "sun.h"
+#include "swap.h"
+#include "ufs.h"
+#include "xfs.h"
+#include "log.h"
+
+static int is_extended(const unsigned int part_type);
+static int can_be_ext(const disk_t *disk_car, const partition_t *partition);
+static int test_structure_i386(list_part_t *list_part);
+#define pt_offset_const(b, n) ((const struct partition_dos *)((b) + 0x1be + \
+ (n) * sizeof(struct partition_dos)))
+#define pt_offset(b, n) ((struct partition_dos *)((b) + 0x1be + \
+ (n) * sizeof(struct partition_dos)))
+
+struct partition_dos {
+ unsigned char boot_ind; /* 0x80 - active */
+ unsigned char head; /* starting head */
+ unsigned char sector; /* starting sector */
+ unsigned char cyl; /* starting cylinder */
+ unsigned char sys_ind; /* What partition type */
+ unsigned char end_head; /* end head */
+ unsigned char end_sector; /* end sector */
+ unsigned char end_cyl; /* end cylinder */
+ unsigned char start4[4]; /* starting sector counting from 0 */
+ unsigned char size4[4]; /* nr of sectors in partition */
+};
+
+
+#define s_cyl(p) (((p)->cyl & (unsigned)0xff) | (((p)->sector << 2) & (unsigned)0x300))
+#define s_head(p) ((p)->head)
+#define s_sect(p) ((p)->sector & (unsigned)0x3f)
+#define e_cyl(p) (((p)->end_cyl & (unsigned)0xff) | (((p)->end_sector << 2) & (unsigned)0x300))
+#define e_head(p) ((p)->end_head)
+#define e_sect(p) ((p)->end_sector & (unsigned)0x3f)
+static uint64_t get_start_sect(const struct partition_dos *p);
+static uint64_t get_nr_sects(const struct partition_dos *p);
+static void log_dos_entry(const disk_t *disk_car, const struct partition_dos*);
+static int get_geometry_from_i386mbr(const unsigned char *buffer, const int verbose, CHS_t *geometry);
+static list_part_t *get_ext_data_i386(disk_t *disk_car, list_part_t *list_part, const int verbose, const int saveheader);
+static void test_MBR_data(list_part_t *list_part);
+static int test_MBR_over(disk_t *disk_car,list_part_t *list_part);
+static int write_mbr_i386(disk_t *disk_car, const list_part_t *list_part, const int ro, const int verbose);
+static int write_all_log_i386(disk_t *disk_car, const list_part_t *list_part, const int ro , const int verbose, const int align);
+static int diff(const disk_t *disk_car,const unsigned char buffer[DEFAULT_SECTOR_SIZE], const unsigned char buffer_org[DEFAULT_SECTOR_SIZE]);
+
+static list_part_t *read_part_i386(disk_t *disk_car, const int verbose, const int saveheader);
+static int write_part_i386(disk_t *disk_car, const list_part_t *list_part, const int ro , const int verbose, const int align);
+static list_part_t *init_part_order_i386(const disk_t *disk_car, list_part_t *list_part);
+static int write_MBR_code_i386(disk_t *disk_car);
+static int write_MBR_code_i386_aux(unsigned char *buffer);
+static list_part_t *add_partition_i386(disk_t *disk_car,list_part_t *list_part, const int verbose, char **current_cmd);
+static void set_prev_status_i386(const disk_t *disk_car, partition_t *partition);
+static void set_next_status_i386(const disk_t *disk_car, partition_t *partition);
+static int set_part_type_i386(partition_t *partition, unsigned int part_type);
+static int is_part_known_i386(const partition_t *partition);
+static void init_structure_i386(const disk_t *disk_car,list_part_t *list_part, const int verbose);
+static int erase_list_part_i386(disk_t *disk_car);
+static int check_part_i386(disk_t *disk_car, const int verbose,partition_t *partition,const int saveheader);
+
+static void partition2_i386_entry(const disk_t *disk_car,const uint64_t pos,const partition_t *partition, struct partition_dos *p);
+static int i386_entry2partition(disk_t *disk_car, const uint64_t offset, partition_t *partition, const struct partition_dos *p, const status_type_t status,const unsigned int order,const int verbose, const int saveheader);
+static const char* errmsg_i386_entry2partition(const errcode_type_t errcode);
+static const char *get_partition_typename_i386(const partition_t *partition);
+static const char *get_partition_typename_i386_aux(const unsigned int part_type_i386);
+static unsigned int get_part_type_i386(const partition_t *partition);
+
+static const struct systypes i386_sys_types[] = {
+ {P_NO_OS, "empty"},
+ {P_12FAT, "FAT12"},
+ {0x02, "XENIX root"},
+ {0x03, "XENIX /usr"},
+ {P_16FAT, "FAT16 <32M"},
+ {P_EXTENDED, "extended"},
+ {P_16FATBD, "FAT16 >32M"},
+ {P_NTFS, "HPFS - NTFS"},
+ {0x09, "AIX data"},
+ {P_OS2MB, "OS/2 Boot Manager"},
+ {P_32FAT, "FAT32"},
+ {P_32FAT_LBA, "FAT32 LBA"},
+ {P_16FATBD_LBA, "FAT16 LBA"},
+ {P_EXTENDX, "extended LBA"},
+ {0x10, "OPUS"},
+ {P_12FATH, "hid. FAT12"},
+ {0x12, "Compaq Diagnostics"},
+ {P_16FATH, "hid. FAT16 <32M"},
+ {P_16FATBDH, "hid. FAT16 >32M"},
+ {P_NTFSH, "hid. HPFS/NTFS"},
+ {0x18, "AST swap"},
+ {0x19, "Willowtech Photon"},
+ {P_32FATH, "hid. FAT32"},
+ {P_32FAT_LBAH, "hid. FAT32 LBA"},
+ {P_16FATBD_LBAH, "hid. FAT16 LBA"},
+ {0x20, "Willowsoft OFS1"},
+ {0x24, "NEC MS-DOS 3.x"},
+ {0x38, "Theos"},
+ {0x3c, "PMagic recovery"},
+ {0x40, "VENIX 80286"},
+ {0x41, "PPC PReP Boot"},
+ {0x42, "W2K Dynamic/SFS"},
+ {0x50, "OnTrack DM RO"},
+ {0x51, "OnTrack DM RW-NOVEL"},
+ {0x52, "CP/M-Microport V/386"},
+ {0x53, "OnTrack DM WO ???"},
+ {0x54, "OnTrack DM DDO"},
+ {0x55, "EZ-Drive"},
+ {0x56, "GoldenBow VFeature"},
+ {0x61, "SpeedStor"},
+ {P_SYSV, "Unixware, HURD, SCO"},
+ {0x64, "NetWare 286"},
+ {P_NETWARE, "NetWare 3.11+"},
+ {0x67, "Novell"},
+ {0x68, "Novell"},
+ {0x69, "Novell"},
+ {0x70, "DiskSecure MB"},
+ {0x75, "PC/IX"},
+ {0x80, "Minix v1.1-1.4a"},
+ {P_OLDLINUX, "Minix / old Linux"},
+ {P_LINSWAP, "Linux Swap"},
+ {P_LINUX, "Linux"},
+ {P_LINUXEXTENDX, "Linux extended"},
+ {0x86, "NT FAT16 V/S set"},
+ {0x87, "HPFS FT mirror-V/S set"},
+ {P_LVM, "Linux LVM"},
+ {0x93, "Amoeba"},
+ {0x94, "Amoeba bad block"},
+ {0xa0, "NoteBIOS save2disk"},
+ {P_FREEBSD, "FreeBSD"},
+ {P_OPENBSD, "OpenBSD"},
+ {0xa8, "Darwin UFS"},
+ {P_NETBSD, "NetBSD"},
+ {0xab, "Darwin boot"},
+ {P_HFS, "HFS"},
+ {0xb7, "BSDI"},
+ {0xb8, "BSDI swap"},
+ {0xbc, "Acronis"},
+ {0xbe, "Solaris boot"},
+ {P_SUN, "Solaris"},
+ {0xc1, "secured FAT12"},
+ {0xc4, "secured FAT16"},
+ {0xc6, "sec. Huge-bad FAT16"},
+ {0xc7, "Syrinx Boot-bad NTFS"},
+ {0xd8, "CP/M-86"},
+ {0xdb, "CP/M"},
+ {0xde, "Dell Utility"},
+ {0xe1, "SpeedStor FAT12 ext"},
+ {0xe3, "DOS RO"},
+ {0xe4, "SpeedStor FAT16 ext"},
+ {P_BEOS, "BeFS"},
+ {0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */
+ {0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
+ {0xf0, "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
+ {0xf1, "Storage Dimensions"},
+ {0xf2, "DOS secondary"},
+ {0xf4, "SpeedStor"},
+ {P_RAID, "Linux RAID"},
+ {0xfe, "LANstep"},
+ {0xff, "Xenix bad block"},
+ {P_NO_OS, NULL }
+};
+
+arch_fnct_t arch_i386= {
+ .part_name="Intel",
+ .part_name_option="partition_i386",
+ .msg_part_type="*=Primary bootable P=Primary L=Logical E=Extended D=Deleted",
+ .read_part=read_part_i386,
+ .write_part=write_part_i386,
+ .init_part_order=init_part_order_i386,
+ .get_geometry_from_mbr=get_geometry_from_i386mbr,
+ .check_part=check_part_i386,
+ .write_MBR_code=write_MBR_code_i386,
+ .add_partition=add_partition_i386,
+ .set_prev_status=set_prev_status_i386,
+ .set_next_status=set_next_status_i386,
+ .test_structure=test_structure_i386,
+ .set_part_type=set_part_type_i386,
+ .is_part_known=is_part_known_i386,
+ .init_structure=init_structure_i386,
+ .erase_list_part=erase_list_part_i386,
+ .get_partition_typename=get_partition_typename_i386,
+ .get_part_type=get_part_type_i386
+};
+
+static unsigned int get_part_type_i386(const partition_t *partition)
+{
+ return partition->part_type_i386;
+}
+
+static void store4_little_endian(unsigned char *cp, unsigned int val)
+{
+ cp[0] = (val & 0xff);
+ cp[1] = ((val >> 8) & 0xff);
+ cp[2] = ((val >> 16) & 0xff);
+ cp[3] = ((val >> 24) & 0xff);
+}
+
+static unsigned int read4_little_endian(const unsigned char *cp)
+{
+ return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8) + ((unsigned int)(cp[2]) << 16) + ((unsigned int)(cp[3]) << 24);
+}
+
+static uint64_t get_start_sect(const struct partition_dos *p)
+{
+ return read4_little_endian(p->start4);
+}
+
+uint64_t get_nr_sects(const struct partition_dos *p)
+{
+ return read4_little_endian(p->size4);
+}
+
+static void set_nr_sects(struct partition_dos *p, unsigned int nr_sects)
+{
+ store4_little_endian(p->size4, nr_sects);
+}
+
+static void set_start_sect(struct partition_dos *p, unsigned int start_sect)
+{
+ store4_little_endian(p->start4, start_sect);
+}
+
+
+int get_geometry_from_i386mbr(const unsigned char *buffer, const int verbose, CHS_t *geometry)
+{
+ unsigned int i;
+ if(verbose>1)
+ {
+ log_trace("get_geometry_from_i386mbr\n");
+ }
+ if((buffer[0x1FE]!=(unsigned char)0x55)||(buffer[0x1FF]!=(unsigned char)0xAA))
+ {
+ return 1;
+ }
+ for(i=0;i<4;i++)
+ {
+ const struct partition_dos *p=pt_offset_const(buffer,i);
+ if(p->sys_ind!=0)
+ {
+ if(geometry->cylinder<e_cyl(p))
+ geometry->cylinder=e_cyl(p);
+ if(geometry->head<e_head(p))
+ geometry->head=e_head(p);
+ if(geometry->sector<e_sect(p))
+ geometry->sector=e_sect(p);
+ }
+ }
+ if(geometry->sector==32 ||
+ (geometry->sector==63 && (geometry->head==16-1 || geometry->head==32-1 || geometry->head==64-1 || geometry->head==128-1 || geometry->head==240-1 || geometry->head==255-1)))
+ log_info("Geometry from i386 MBR: head=%u sector=%u\n",geometry->head+1,geometry->sector);
+ else
+ {
+ if(geometry->sector>0)
+ log_warning("Geometry from i386 MBR: head=%u sector=%u\n",geometry->head+1,geometry->sector);
+ geometry->cylinder=0;
+ geometry->head=0;
+ geometry->sector=0;
+ }
+ return 0;
+}
+
+static list_part_t *init_part_order_i386(const disk_t *disk_car, list_part_t *list_part)
+{
+ int nbr_log=0;
+ int nbr_prim=0;
+ list_part_t *element;
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ switch(element->part->status)
+ {
+ case STATUS_PRIM:
+ case STATUS_PRIM_BOOT:
+ case STATUS_EXT:
+ element->part->order=++nbr_prim;
+ break;
+ case STATUS_LOG:
+ element->part->order=(++nbr_log)+4;
+ break;
+ default:
+ log_critical("init_part_order_i386: severe error\n");
+ break;
+ }
+ }
+ return list_part;
+}
+
+
+static list_part_t *read_part_i386(disk_t *disk_car, const int verbose, const int saveheader)
+{
+ unsigned int i;
+ int res=0;
+ CHS_t geometry;
+ list_part_t *new_list_part=NULL;
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+ aff_buffer(BUFFER_RESET,"Q");
+ if(disk_car->read(disk_car,disk_car->sector_size, buffer, (uint64_t)0))
+ {
+ aff_buffer(BUFFER_ADD, msg_PART_RD_ERR);
+ free(buffer);
+ return NULL;
+ }
+ geometry.cylinder=0;
+ geometry.head=0;
+ geometry.sector=0;
+ if(get_geometry_from_i386mbr(buffer,verbose,&geometry)!=0)
+ {
+ aff_buffer(BUFFER_ADD,msg_TBL_NMARK);
+ free(buffer);
+ return NULL;
+ }
+ for(i=0;i<4;i++)
+ {
+ const struct partition_dos *p=pt_offset(buffer,i);
+ status_type_t status=STATUS_PRIM;
+ switch(p->sys_ind)
+ {
+ case P_NO_OS:
+ break;
+ case P_EXTENDX:
+ case P_EXTENDED:
+ case P_LINUXEXTENDX:
+ status=STATUS_EXT;
+ /* don't put a break */
+ default:
+ {
+ int insert_error=0;
+ partition_t *new_partition=partition_new(&arch_i386);
+ i386_entry2partition(disk_car, (uint64_t)0, new_partition, p, status,i+1,verbose,saveheader);
+ if(verbose>1)
+ log_dos_entry(disk_car,p);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,new_partition);
+ if(new_partition->errcode!=BAD_NOERR)
+ {
+ aff_buffer(BUFFER_ADD,"%s\n",errmsg_i386_entry2partition(new_partition->errcode));
+ res|=1;
+ }
+ new_list_part=insert_new_partition(new_list_part,new_partition, 0, &insert_error);
+ if(insert_error>0)
+ free(new_partition);
+ }
+ break;
+ }
+ }
+ test_MBR_data(new_list_part);
+ test_MBR_over(disk_car,new_list_part);
+ new_list_part=get_ext_data_i386(disk_car,new_list_part,verbose,saveheader);
+ get_geometry_from_list_part(disk_car, new_list_part, verbose);
+ free(buffer);
+ return new_list_part;
+}
+
+static void test_MBR_data(list_part_t *list_part)
+{
+ list_part_t *element;
+ unsigned int nb_dos=0, nb_hidden=0, nb_mb=0, nb_ext=0, nb_boot=0;
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ const partition_t *partition=element->part;
+ switch(partition->status)
+ {
+ case STATUS_PRIM_BOOT:
+ nb_boot++;
+ case STATUS_PRIM:
+ switch(partition->part_type_i386)
+ {
+ case P_12FAT:
+ case P_16FAT:
+ case P_16FATBD:
+ nb_dos++;
+ break;
+ case P_16FATBDH:
+ case P_16FATH:
+ case P_NTFSH:
+ nb_hidden++;
+ break;
+ case P_OS2MB:
+ nb_mb++;
+ break;
+ }
+ break;
+ case STATUS_EXT:
+ nb_ext++;
+ break;
+ default:
+ log_critical("test_MBR_data: severe error\n");
+ break;
+ }
+ }
+ if(nb_dos>1)
+ aff_buffer(BUFFER_ADD,msg_ONLY_ONE_DOS);
+ if(nb_ext>1)
+ aff_buffer(BUFFER_ADD,msg_ONLY_ONE_EXT);
+ /* S'il y a des partitions caches, il faut un MB */
+ /* Obsolete
+ if(nb_hidden>0 && nb_mb==0)
+ aff_buffer(BUFFER_ADD,msg_NO_OS2MB);
+ */
+ /* Nombre de partition bootable */
+ if(nb_boot==0)
+ aff_buffer(BUFFER_ADD,msg_NO_BOOTABLE);
+ else
+ if(nb_boot>1)
+ aff_buffer(BUFFER_ADD,msg_ONLY1MUSTBOOT);
+}
+
+static list_part_t *get_ext_data_i386(disk_t *disk_car, list_part_t *list_part, const int verbose, const int saveheader)
+{
+ list_part_t *element;
+ int res=0;
+ partition_t *partition_main_ext=NULL;
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ if(element->part->status==STATUS_EXT)
+ partition_main_ext=element->part;
+ }
+ if(partition_main_ext!=NULL)
+ {
+ partition_t *partition_ext=partition_main_ext;
+ partition_t *partition_next_ext=NULL;
+ unsigned int i;
+ unsigned int order=5;
+ do
+ {
+ unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ int nb_hidden=0, nb_mb=0, nb_part=0, nb_ext=0, nb_boot=0;
+ if(disk_car->read(disk_car,sizeof(buffer), &buffer, partition_ext->part_offset)!=0)
+ return list_part;
+ if((buffer[0x1FE]!=(unsigned char)0x55)||(buffer[0x1FF]!=(unsigned char)0xAA))
+ {
+ aff_buffer(BUFFER_ADD,"\ntest_logical: " msg_TBL_NMARK);
+ return list_part;
+ }
+ for(i=0;i<4;i++)
+ {
+ const struct partition_dos *p=pt_offset(buffer,i);
+ if(p->boot_ind==(unsigned char)0x80)
+ nb_boot++;
+ switch(p->sys_ind)
+ {
+ case P_16FATBDH:
+ case P_16FATH:
+ case P_NTFSH:
+ nb_hidden++;
+ break;
+ case P_OS2MB:
+ nb_mb++;
+ break;
+ case P_EXTENDX:
+ case P_EXTENDED:
+ case P_LINUXEXTENDX:
+ nb_ext++;
+ break;
+ case P_NO_OS:
+ break;
+ default:
+ nb_part++;
+ }
+ }
+ if(nb_hidden>0)
+ aff_buffer(BUFFER_ADD,"Partition must not be hidden\n");
+ if(nb_mb>0)
+ aff_buffer(BUFFER_ADD,"Multiboot must be a primary partition, not a logical\n");
+ if(nb_ext>1)
+ aff_buffer(BUFFER_ADD,"A logical partition must not have more than one link to another logical partition\n");
+ if(nb_part>1)
+ aff_buffer(BUFFER_ADD,"A logical partition must contain only one partition\n");
+ if(nb_boot>0)
+ aff_buffer(BUFFER_ADD,"Logical partition must not be bootable\n");
+ partition_next_ext=NULL;
+ for(i=0;i<4;i++)
+ {
+ const struct partition_dos *p=pt_offset(buffer,i);
+ if(p->sys_ind!=0)
+ {
+ int insert_error=0;
+ partition_t *new_partition=partition_new(&arch_i386);
+ new_partition->order=order;
+ if(verbose>1)
+ log_dos_entry(disk_car,p);
+ if(is_extended(p->sys_ind))
+ {
+ partition_next_ext=new_partition;
+ i386_entry2partition(disk_car, partition_main_ext->part_offset, new_partition, p, STATUS_EXT_IN_EXT,order,verbose,saveheader);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,new_partition);
+ if(new_partition->errcode!=BAD_NOERR)
+ {
+ aff_buffer(BUFFER_ADD,"%s\n",errmsg_i386_entry2partition(new_partition->errcode));
+ res=1;
+ }
+ {
+ if((new_partition->part_offset<=partition_main_ext->part_offset) ||
+ (new_partition->part_offset+new_partition->part_size-1 > partition_main_ext->part_offset+partition_main_ext->part_size-1))
+ { /* Must be IN partition_main_ext */
+ res=1;
+ aff_buffer(BUFFER_ADD,"Must be in extended partition\n");
+ aff_part_buffer(AFF_PART_ORDER,disk_car,partition_main_ext);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,new_partition);
+ }
+ else
+ {
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ partition_t *partition=element->part;
+ if(partition->status==STATUS_EXT_IN_EXT)
+ {
+ if(((partition->part_offset>=new_partition->part_offset) && (partition->part_offset<=new_partition->part_offset+new_partition->part_size-1)) ||
+ ((partition->part_offset+partition->part_size-1>=new_partition->part_offset) && (partition->part_offset+partition->part_size-1<=new_partition->part_offset+partition->part_size-1)))
+ { /* New Partition start or end mustn't been in partition */
+ res=1;
+ aff_buffer(BUFFER_ADD, "Logical partition must be in its own extended partition\n");
+ aff_part_buffer(AFF_PART_ORDER,disk_car,partition);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,new_partition);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ i386_entry2partition(disk_car,partition_ext->part_offset, new_partition, p, STATUS_LOG,order,verbose,saveheader);
+ order++;
+ if(verbose>1)
+ log_dos_entry(disk_car,p);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,new_partition);
+ if(new_partition->errcode!=BAD_NOERR)
+ {
+ aff_buffer(BUFFER_ADD,"%s\n",errmsg_i386_entry2partition(new_partition->errcode));
+ res=1;
+ }
+ {
+ if((new_partition->part_offset<=partition_main_ext->part_offset) ||
+ (new_partition->part_offset+new_partition->part_size-1 > partition_main_ext->part_offset+partition_main_ext->part_size-1))
+ { /* Must be IN partition_main_ext */
+ res=1;
+ aff_buffer(BUFFER_ADD, msg_SAME_SPACE);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,partition_main_ext);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,new_partition);
+ }
+ }
+ }
+ list_part=insert_new_partition(list_part, new_partition, 0, &insert_error);
+ if(insert_error>0)
+ free(new_partition);
+ }
+ }
+ partition_ext=partition_next_ext;
+ } while ((partition_ext!=NULL) && (order<30));
+ }
+ return list_part;
+}
+
+static int test_MBR_over(disk_t *disk_car,list_part_t *list_part)
+{/* Test if partitions overlap */
+ int res=0;
+ list_part_t *element;
+ for(element=list_part;element!=NULL;element=element->next)
+ if(element->next!=NULL &&
+ element->part->part_offset + element->part->part_size - 1 >= element->next->part->part_offset)
+ {
+ res=1;
+ aff_buffer(BUFFER_ADD, msg_SAME_SPACE);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,element->part);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,element->next->part);
+ }
+ return res;
+}
+
+int write_part_i386(disk_t *disk_car, const list_part_t *list_part, const int ro, const int verbose, const int align)
+{
+ int res=0;
+ res+=write_mbr_i386(disk_car,list_part,ro,verbose);
+ res+=write_all_log_i386(disk_car,list_part,ro,verbose,align);
+ return res;
+}
+
+static int write_mbr_i386(disk_t *disk_car, const list_part_t *list_part, const int ro, const int verbose)
+{
+ const list_part_t *element;
+ unsigned char *buffer=MALLOC(disk_car->sector_size);
+ unsigned char *buffer_org=MALLOC(disk_car->sector_size);
+ if(verbose>0)
+ {
+ log_trace("\nwrite_mbr_i386: starting...\n");
+ }
+ if(disk_car->read(disk_car,DEFAULT_SECTOR_SIZE, buffer_org, (uint64_t)0))
+ {
+ log_error(msg_PART_RD_ERR);
+ memset(buffer_org,0,DEFAULT_SECTOR_SIZE);
+ }
+ memset(buffer,0,DEFAULT_SECTOR_SIZE);
+ if((buffer_org[0x1FE]==0x55) && (buffer_org[0x1FF]==0xAA))
+ {
+ memcpy(buffer,buffer_org,TAB_PART);
+ buffer[0x1FE]=0x55;
+ buffer[0x1FF]=0xAA;
+ } else {
+ if(verbose>0)
+ log_info("Store new MBR code\n");
+ write_MBR_code_i386_aux(buffer);
+ }
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ switch(element->part->status)
+ {
+ case STATUS_PRIM:
+ case STATUS_PRIM_BOOT:
+ case STATUS_EXT:
+ if((element->part->order>=1) && (element->part->order<=4))
+ {
+ partition2_i386_entry(disk_car,(uint64_t)0,element->part,
+ pt_offset(buffer,element->part->order-1));
+ }
+ break;
+ case STATUS_LOG:
+ break;
+ default:
+ log_critical("write_mbr_i386: severe error\n");
+ break;
+ }
+ }
+ if(verbose>1)
+ {
+ int i;
+ for(i=0;i<4;i++)
+ {
+ const struct partition_dos *p=pt_offset(buffer,i);
+ log_dos_entry(disk_car,p);
+ }
+ diff(disk_car,buffer,buffer_org);
+ }
+ if(ro==0)
+ {
+ if(disk_car->write(disk_car,DEFAULT_SECTOR_SIZE, buffer, (uint64_t)0))
+ {
+ free(buffer_org);
+ free(buffer);
+ return 1;
+ }
+ }
+ free(buffer_org);
+ free(buffer);
+ return 0;
+}
+
+static int write_all_log_i386(disk_t *disk_car, const list_part_t *list_part, const int ro, const int verbose, const int align)
+{
+ const list_part_t *element;
+ const list_part_t *pos_ext=NULL;
+ uint64_t current_pos;
+ partition_t *bloc_nextext;
+ int res=0;
+ if(verbose>0)
+ log_trace("write_all_log_i386: starting...\n");
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ if(element->part->status==STATUS_EXT)
+ {
+ if(is_extended(element->part->part_type_i386))
+ {
+ if(pos_ext!=NULL)
+ log_critical("write_all_log_i386: pos_ext already defined\n");
+ pos_ext=element;
+ }
+ else
+ {
+ log_critical("write_all_log_i386: STATUS_EXT with bad part_type\n");
+ }
+ }
+ }
+ if(pos_ext==NULL)
+ {
+ log_info(msg_NO_EXT_PART);
+ return 0;
+ }
+ current_pos=pos_ext->part->part_offset;
+ bloc_nextext=(partition_t *)MALLOC(sizeof(*bloc_nextext));
+ bloc_nextext->part_type_i386=P_EXTENDED; /* Never P_EXTENDX */
+ if(pos_ext->next==NULL || (pos_ext->next->part->status!=STATUS_LOG))
+ {
+ unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ unsigned char buffer_org[DEFAULT_SECTOR_SIZE];
+ if(verbose>0)
+ {
+ log_info("write_all_log_i386: CHS: %u/%u/%u,lba=%lu\n", offset2cylinder(disk_car,current_pos), offset2head(disk_car,current_pos), offset2sector(disk_car,current_pos),(long unsigned)(current_pos/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car,sizeof(buffer_org), &buffer_org, current_pos))
+ {
+ memset(buffer_org,0,DEFAULT_SECTOR_SIZE);
+ }
+ memset(buffer,0,DEFAULT_SECTOR_SIZE);
+ memcpy(buffer,buffer_org,TAB_PART);
+ buffer[0x1FE]=0x55;
+ buffer[0x1FF]=0xAA;
+ if(ro)
+ {
+ if(verbose>1)
+ diff(disk_car,buffer,buffer_org);
+ }
+ else
+ {
+ if(disk_car->write(disk_car,sizeof(buffer), &buffer, current_pos))
+ {
+ res=1;
+ }
+ }
+ }
+ else
+ {
+ for(element=pos_ext->next;(element!=NULL) && (element->part->status==STATUS_LOG);element=element->next)
+ {
+ int j;
+ unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ unsigned char buffer_org[DEFAULT_SECTOR_SIZE];
+ if(verbose>0)
+ {
+ log_info("write_all_log_i386: CHS: %u/%u/%u,lba=%lu\n", offset2cylinder(disk_car,current_pos), offset2head(disk_car,current_pos), offset2sector(disk_car,current_pos),(long unsigned)(current_pos/disk_car->sector_size));
+ }
+ if(disk_car->read(disk_car,sizeof(buffer_org), &buffer_org, current_pos))
+ {
+ memset(buffer_org,0,DEFAULT_SECTOR_SIZE);
+ }
+ memset(buffer,0,DEFAULT_SECTOR_SIZE);
+ memcpy(buffer,buffer_org,TAB_PART);
+ buffer[0x1FE]=0x55;
+ buffer[0x1FF]=0xAA;
+ partition2_i386_entry(disk_car,current_pos,element->part, pt_offset(buffer,0));
+ if(element->next!=NULL && (element->next->part->status==STATUS_LOG))
+ { /* Construit le pointeur vers la prochaine partition logique */
+ CHS_t nextext_start;
+ bloc_nextext->part_offset=element->next->part->part_offset-disk_car->sector_size;
+ offset2CHS(disk_car,bloc_nextext->part_offset,&nextext_start);
+ if(nextext_start.sector!=disk_car->CHS.sector)
+ {
+ if(nextext_start.head>0)
+ nextext_start.head--;
+ else
+ {
+ nextext_start.head=disk_car->CHS.head;
+ nextext_start.cylinder--;
+ }
+ }
+ nextext_start.sector=1;
+ if(verbose>1)
+ log_verbose("nextext_start %u/%u/%u %lu ? %lu\n", nextext_start.cylinder,nextext_start.head,nextext_start.sector,
+ (long unsigned)(CHS2offset(disk_car,&nextext_start)/disk_car->sector_size),
+ (long unsigned)((element->part->part_offset+element->part->part_size-1)/disk_car->sector_size));
+ if(CHS2offset(disk_car,&nextext_start)<=element->part->part_offset+element->part->part_size-1)
+ {
+ offset2CHS(disk_car,bloc_nextext->part_offset,&nextext_start);
+ nextext_start.sector=1;
+ if(verbose>1)
+ log_verbose("nextext_start %u/%u/%u %lu ? %lu\n", nextext_start.cylinder,nextext_start.head,nextext_start.sector,
+ (long unsigned)(CHS2offset(disk_car,&nextext_start)/disk_car->sector_size),
+ (long unsigned)((element->part->part_offset+element->part->part_size-1)/disk_car->sector_size));
+ if(CHS2offset(disk_car,&nextext_start)<=element->part->part_offset+element->part->part_size-1)
+ {
+ offset2CHS(disk_car,bloc_nextext->part_offset,&nextext_start);
+ }
+ }
+ if(verbose>1)
+ log_verbose("nextext_start %u/%u/%u %lu ? %lu\n", nextext_start.cylinder,nextext_start.head,nextext_start.sector,
+ (long unsigned)(CHS2offset(disk_car,&nextext_start)/disk_car->sector_size),
+ (long unsigned)((element->part->part_offset+element->part->part_size-1)/disk_car->sector_size));
+ bloc_nextext->part_offset=CHS2offset(disk_car,&nextext_start);
+ /* log_debug("table[i]->next=%p table[i+1]=%p\n",table[i]->next,table[i+1]); */
+ bloc_nextext->part_size=(uint64_t)element->next->part->part_offset+element->next->part->part_size-bloc_nextext->part_offset;
+ partition2_i386_entry(disk_car,pos_ext->part->part_offset,bloc_nextext, pt_offset(buffer,1));
+ }
+ if(ro)
+ {
+ if(verbose>1)
+ {
+ for(j=0;j<4;j++)
+ {
+ const struct partition_dos *p=pt_offset(buffer,j);
+ if(p->sys_ind!=0)
+ log_dos_entry(disk_car,p);
+ }
+ diff(disk_car,buffer,buffer_org);
+ }
+ }
+ else
+ {
+ if(disk_car->write(disk_car,sizeof(buffer), &buffer, current_pos))
+ {
+ res=1;
+ }
+ }
+ current_pos=bloc_nextext->part_offset;
+ }
+ }
+ free(bloc_nextext);
+ return res;
+}
+
+static int diff(const disk_t *disk_car, const unsigned char buffer[DEFAULT_SECTOR_SIZE], const unsigned char buffer_org[DEFAULT_SECTOR_SIZE])
+{
+ int j;
+ if(memcmp(buffer,buffer_org,DEFAULT_SECTOR_SIZE))
+ {
+ log_info("\nSectors are different.\n");
+ log_info("buffer_org\n");
+ for(j=0;j<4;j++)
+ {
+ const struct partition_dos *p=pt_offset_const(buffer_org,j);
+ if(p->sys_ind!=0)
+ log_dos_entry(disk_car,p);
+ }
+ log_info("buffer\n");
+ for(j=0;j<4;j++)
+ {
+ const struct partition_dos *p=pt_offset_const(buffer,j);
+ if(p->sys_ind!=0)
+ log_dos_entry(disk_car,p);
+ }
+ for(j=0;j<DEFAULT_SECTOR_SIZE;j++)
+ if(buffer_org[j]!=buffer[j])
+ log_info("%02X %02X %02X\n", j, buffer_org[j], buffer[j]);
+ log_info("\n");
+ }
+ return 0;
+}
+
+static int write_MBR_code_i386(disk_t *disk_car)
+{
+ unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ if(disk_car->read(disk_car,DEFAULT_SECTOR_SIZE, buffer, (uint64_t)0))
+ {
+ log_error(msg_PART_RD_ERR);
+ memset(buffer,0,sizeof(buffer));
+ }
+ write_MBR_code_i386_aux(buffer);
+ if(disk_car->write(disk_car,DEFAULT_SECTOR_SIZE, buffer, (uint64_t)0))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+static int write_MBR_code_i386_aux(unsigned char *buffer)
+{
+ /* od -t x1 -v testdisk.b
+ Thanks to Neil Turton for writing it */
+ const unsigned char mbr_code_testdisk[DEFAULT_SECTOR_SIZE]={
+ 0xfc, 0x31, 0xc0, 0x8e, 0xd0, 0x31, 0xe4, 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x00, 0x7c, 0xbf, 0x00,
+ 0x06, 0xb9, 0x00, 0x01, 0xf3, 0xa5, 0xbe, 0xee, 0x07, 0xb0, 0x08, 0xea, 0x20, 0x06, 0x00, 0x00,
+ 0x80, 0x3e, 0xb3, 0x07, 0xff, 0x75, 0x04, 0x88, 0x16, 0xb3, 0x07, 0x80, 0x3c, 0x00, 0x74, 0x04,
+ 0x08, 0x06, 0xaf, 0x07, 0x83, 0xee, 0x10, 0xd0, 0xe8, 0x73, 0xf0, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xbe, 0xbe,
+ 0x07, 0xb0, 0x00, 0xb9, 0x04, 0x00, 0x80, 0x3c, 0x00, 0x75, 0x6e, 0xfe, 0xc0, 0x83, 0xc6, 0x10,
+ 0xe2, 0xf4, 0x31, 0xdb, 0xb4, 0x0e, 0xbe, 0x9d, 0x07, 0x8a, 0x0e, 0xaf, 0x07, 0xac, 0xd0, 0xe9,
+ 0x73, 0x02, 0xcd, 0x10, 0x08, 0xc9, 0x75, 0xf5, 0xb0, 0x3a, 0xcd, 0x10, 0x31, 0xc0, 0xcd, 0x16,
+ 0x3c, 0x00, 0x74, 0xf8, 0xbe, 0x8b, 0x07, 0xb9, 0x02, 0x00, 0xe8, 0xba, 0x00, 0x3c, 0x0d, 0x74,
+ 0xb4, 0x3c, 0x61, 0x72, 0x06, 0x3c, 0x7a, 0x77, 0x02, 0x2c, 0x20, 0x88, 0xc3, 0xbe, 0x9d, 0x07,
+ 0x8a, 0x0e, 0xaf, 0x07, 0xac, 0xd0, 0xe9, 0x73, 0x04, 0x38, 0xc3, 0x74, 0x06, 0x08, 0xc9, 0x75,
+ 0xf3, 0xeb, 0xaf, 0xb8, 0x0d, 0x0e, 0x31, 0xdb, 0xcd, 0x10, 0x8d, 0x84, 0x62, 0x00, 0x3c, 0x07,
+ 0x75, 0x07, 0xb0, 0x1f, 0xa2, 0xaf, 0x07, 0xeb, 0x99, 0x31, 0xd2, 0xb9, 0x01, 0x00, 0x3c, 0x04,
+ 0x74, 0x11, 0x73, 0xf3, 0x30, 0xe4, 0xb1, 0x04, 0xd2, 0xe0, 0xbe, 0xbe, 0x07, 0x01, 0xc6, 0x8a,
+ 0x16, 0xb3, 0x07, 0xbf, 0x05, 0x00, 0x56, 0xf6, 0xc2, 0x80, 0x74, 0x31, 0xb4, 0x41, 0xbb, 0xaa,
+ 0x55, 0x52, 0xcd, 0x13, 0x5a, 0x5e, 0x56, 0x72, 0x1e, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x18, 0xf6,
+ 0xc1, 0x01, 0x74, 0x13, 0x8b, 0x44, 0x08, 0x8b, 0x5c, 0x0a, 0xbe, 0x8d, 0x07, 0x89, 0x44, 0x08,
+ 0x89, 0x5c, 0x0a, 0xb4, 0x42, 0xeb, 0x0c, 0x8a, 0x74, 0x01, 0x8b, 0x4c, 0x02, 0xb8, 0x01, 0x02,
+ 0xbb, 0x00, 0x7c, 0x50, 0xc6, 0x06, 0x8f, 0x07, 0x01, 0xcd, 0x13, 0x58, 0x5e, 0x73, 0x05, 0x4f,
+ 0x75, 0xb4, 0xeb, 0x93, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0xf6, 0xea, 0x00, 0x7c, 0x00,
+ 0x00, 0xbe, 0x83, 0x07, 0xb9, 0x0a, 0x00, 0x50, 0xb4, 0x0e, 0x31, 0xdb, 0xac, 0xcd, 0x10, 0xe2,
+ 0xfb, 0x58, 0xc3, 0x54, 0x65, 0x73, 0x74, 0x44, 0x69, 0x73, 0x6b, 0x0d, 0x0a, 0x10, 0x00, 0x01,
+ 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33,
+ 0x34, 0x46, 0x00, 0x00, 0x41, 0x4e, 0x44, 0x54, 0x6d, 0x62, 0x72, 0x00, 0x02, 0x02, 0x02, 0x1f,
+ 0xc7, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa,
+ };
+ memcpy(buffer,&mbr_code_testdisk,TAB_PART);
+ buffer[0x1FE]=(unsigned char)0x55;
+ buffer[0x1FF]=(unsigned char)0xAA;
+ return 0;
+}
+
+static void partition2_i386_entry(const disk_t *disk_car, const uint64_t pos, const partition_t *partition, struct partition_dos *p)
+{
+ CHS_t start,end;
+ offset2CHS(disk_car,partition->part_offset,&start);
+ offset2CHS(disk_car,partition->part_offset+partition->part_size-disk_car->sector_size,&end);
+ if(partition->status==STATUS_PRIM_BOOT)
+ p->boot_ind=0x80;
+ else
+ p->boot_ind=0; /* Non bootable */
+ p->sys_ind=partition->part_type_i386;
+ if(((partition->part_offset-pos)/disk_car->sector_size)<=0xFFFFFFFF)
+ set_start_sect(p,(partition->part_offset-pos)/disk_car->sector_size);
+ else
+ set_start_sect(p,0xFFFFFFFF);
+ if(start.cylinder>1023)
+ { /* Partition Magic 5 uses CHS=(1023,0,1) if extended or last logical *
+ * Linux fdisk and TestDisk use CHS=(1023,lastH,lastS) */
+ p->head=(unsigned char)disk_car->CHS.head;
+ p->sector=(unsigned char)(disk_car->CHS.sector|((1023>>8)<<6));
+ p->cyl=(unsigned char)1023;
+ }
+ else
+ {
+ p->head=(unsigned char)start.head;
+ p->sector=(unsigned char)(start.sector|((start.cylinder>>8)<<6));
+ p->cyl=(unsigned char)(start.cylinder);
+ }
+ if(end.cylinder>1023)
+ {
+ p->end_head=(unsigned char)disk_car->CHS.head;
+ p->end_sector=(unsigned char)(disk_car->CHS.sector|((1023>>8)<<6));
+ p->end_cyl=(unsigned char)1023;
+ }
+ else
+ {
+ p->end_head=(unsigned char)end.head;
+ p->end_sector=(unsigned char)(end.sector|((end.cylinder>>8)<<6));
+ p->end_cyl=(unsigned char)end.cylinder;
+ }
+ if((partition->part_size/disk_car->sector_size)<=0xFFFFFFFF)
+ set_nr_sects(p,partition->part_size/disk_car->sector_size);
+ else
+ set_nr_sects(p,0xFFFFFFFF);
+}
+
+static int i386_entry2partition(disk_t *disk_car, const uint64_t offset, partition_t *partition, const struct partition_dos *p, const status_type_t status,const unsigned int order,const int verbose, const int saveheader)
+{
+ CHS_t start,end;
+ CHS_t start_calculated,end_calculated;
+ partition_reset(partition, &arch_i386);
+ partition->part_type_i386=p->sys_ind;
+ partition->part_offset=offset+(uint64_t)get_start_sect(p)*disk_car->sector_size;
+ partition->order=order;
+ partition->part_size=(uint64_t)get_nr_sects(p)*disk_car->sector_size;
+
+ offset2CHS(disk_car,partition->part_offset,&start_calculated);
+ offset2CHS(disk_car,partition->part_offset+partition->part_size-disk_car->sector_size,&end_calculated);
+
+
+ start.cylinder=s_cyl(p);
+ start.head=s_head(p);
+ start.sector=s_sect(p);
+ end.cylinder=e_cyl(p);
+ end.head=e_head(p);
+ end.sector=e_sect(p);
+ switch(status)
+ {
+ case STATUS_PRIM:
+ if(is_extended(partition->part_type_i386))
+ {
+ partition->status=STATUS_EXT;
+ partition->upart_type=UP_EXTENDED;
+ }
+ else
+ if(p->boot_ind!=0)
+ partition->status=STATUS_PRIM_BOOT;
+ else
+ partition->status=status;
+ break;
+ default:
+ partition->status=status;
+ break;
+ }
+ /* Check CHS */
+ if((start.sector==0)||(start.sector>disk_car->CHS.sector))
+ {
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_SS;
+ }
+ if((end.sector==0)||(end.sector>disk_car->CHS.sector))
+ {
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_ES;
+ }
+ if(start.head>disk_car->CHS.head)
+ {
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_SH;
+ }
+ if(start.cylinder>disk_car->CHS.cylinder)
+ {
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_SC;
+ }
+ if(end.head>disk_car->CHS.head)
+ {
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_EH;
+ }
+ if(end.cylinder>disk_car->CHS.cylinder)
+ {
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_EC;
+ }
+ if(((start_calculated.cylinder<=1023)&& (C_H_S2offset(disk_car,start.cylinder,start.head,start.sector)!=partition->part_offset))
+ || ((start_calculated.cylinder>1023)&&(start.cylinder!=1023)&&(start.cylinder!=(start_calculated.cylinder&1023))))
+ {
+ log_error("BAD_RS LBA=%lu %lu\n",(long unsigned)(partition->part_offset/disk_car->sector_size),C_H_S2LBA(disk_car,start.cylinder,start.head,start.sector));
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_RS;
+ }
+ if(((end_calculated.cylinder<=1023)&& (C_H_S2offset(disk_car,end.cylinder,end.head,end.sector)!=partition->part_offset+partition->part_size-disk_car->sector_size))
+ || ((end_calculated.cylinder>1023)&&(end.cylinder!=1023)&&(end.cylinder!=(end_calculated.cylinder&1023))))
+ {
+ if(partition->errcode==BAD_NOERR)
+ partition->errcode=BAD_SCOUNT;
+ }
+ /* Check partition and load partition name */
+ partition->arch->check_part(disk_car,verbose,partition,saveheader);
+ return 0;
+}
+
+static const char* errmsg_i386_entry2partition(const errcode_type_t errcode)
+{
+ switch(errcode)
+ {
+ case BAD_SS: return msg_BAD_S_SECT;
+ case BAD_ES: return msg_BAD_E_SECT;
+ case BAD_SH: return msg_BAD_S_HEAD;
+ case BAD_EH: return msg_BAD_E_HEAD;
+ case BAD_EBS: return msg_END_BFR_START;
+ case BAD_RS: return msg_BAD_RS;
+ case BAD_SC: return msg_BAD_S_CYL;
+ case BAD_EC: return msg_BAD_E_CYL;
+ case BAD_SCOUNT: return msg_BAD_SCOUNT;
+ case BAD_NOERR: return "";
+ }
+ log_critical("errmsg_i386_entry2partition: unhandled error\n");
+ return "";
+}
+
+static void log_dos_entry(const disk_t *disk_car, const struct partition_dos *entree)
+{
+ if(get_partition_typename_i386_aux(entree->sys_ind)!=NULL)
+ log_info(" %-20s ", get_partition_typename_i386_aux(entree->sys_ind));
+ else
+ log_info(" Sys=%02X ", entree->sys_ind);
+ log_info("%4u %3u %2u"
+ " %4u %3u %2u"
+ " %10lu"
+ " %10lu\n",
+ s_cyl(entree),s_head(entree),s_sect(entree),
+ e_cyl(entree),e_head(entree),e_sect(entree),
+ (long unsigned)get_start_sect(entree),(long unsigned)get_nr_sects(entree));
+}
+
+static int can_be_ext(const disk_t *disk_car, const partition_t *partition)
+{
+ return((offset2head(disk_car,partition->part_offset)>0)&&
+ (offset2cylinder(disk_car,partition->part_offset)!=0 ||
+ offset2head(disk_car,partition->part_offset)!=1 ||
+ offset2sector(disk_car,partition->part_offset)!=1));
+}
+
+static int test_structure_i386(list_part_t *list_part)
+{ /* Return 1 if bad*/
+ int nbr_prim=0, nbr_prim_boot=0, nbr_log_block=0;
+ list_part_t *first_log=NULL;
+ list_part_t *new_list_part=NULL;
+ list_part_t *element;
+ int res;
+ for(element=list_part;element!=NULL;element=element->next)
+ {
+ switch(element->part->status)
+ {
+ case STATUS_LOG:
+ if(first_log==NULL)
+ {
+ first_log=element;
+ nbr_log_block++;
+ }
+ if(is_extended(element->part->part_type_i386))
+ {
+ return 1;
+ }
+ break;
+ case STATUS_PRIM_BOOT:
+ if(nbr_prim_boot++)
+ return 1;
+ case STATUS_PRIM:
+ nbr_prim++;
+ first_log=NULL;
+ break;
+ case STATUS_DELETED:
+ break;
+ default:
+ log_critical("test_structure_i386: severe error\n");
+ break;
+ }
+ }
+ if(nbr_log_block>1 || nbr_log_block+nbr_prim>4)
+ return 1;
+ 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 is_extended(const unsigned int part_type)
+{
+ return (part_type==(const unsigned char)P_EXTENDX || part_type==(const unsigned char)P_EXTENDED || part_type==(const unsigned char)P_LINUXEXTENDX);
+}
+
+static list_part_t *add_partition_i386_cli(disk_t *disk_car,list_part_t *list_part, const int verbose, char **current_cmd)
+{
+ CHS_t start,end;
+ partition_t *new_partition=partition_new(&arch_i386);
+ start.cylinder=0;
+ start.head=0;
+ start.sector=1;
+ end.cylinder=disk_car->CHS.cylinder;
+ end.head=disk_car->CHS.head;
+ end.sector=disk_car->CHS.sector;
+ while(*current_cmd[0]==',')
+ (*current_cmd)++;
+ while(1)
+ {
+ if(strncmp(*current_cmd,"c,",2)==0)
+ {
+ (*current_cmd)+=2;
+ start.cylinder=ask_number_cli(current_cmd, start.cylinder,0,disk_car->CHS.cylinder,"Enter the starting cylinder ");
+ }
+ else if(strncmp(*current_cmd,"h,",2)==0)
+ {
+ (*current_cmd)+=2;
+ start.head=ask_number_cli(current_cmd, start.head,0,disk_car->CHS.head,"Enter the starting head ");
+ }
+ else if(strncmp(*current_cmd,"s,",2)==0)
+ {
+ (*current_cmd)+=2;
+ start.sector=ask_number_cli(current_cmd, start.sector,1,disk_car->CHS.sector,"Enter the starting sector ");
+ }
+ else if(strncmp(*current_cmd,"C,",2)==0)
+ {
+ (*current_cmd)+=2;
+ end.cylinder=ask_number_cli(current_cmd, end.cylinder,start.cylinder,disk_car->CHS.cylinder,"Enter the ending cylinder ");
+ }
+ else if(strncmp(*current_cmd,"H,",2)==0)
+ {
+ (*current_cmd)+=2;
+ end.head=ask_number_cli(current_cmd, end.head,0,disk_car->CHS.head,"Enter the ending head ");
+ }
+ else if(strncmp(*current_cmd,"S,",2)==0)
+ {
+ (*current_cmd)+=2;
+ end.sector=ask_number_cli(current_cmd, end.sector,1,disk_car->CHS.sector,"Enter the ending sector ");
+ }
+ else if(strncmp(*current_cmd,"T,",2)==0)
+ {
+ (*current_cmd)+=2;
+ change_part_type(disk_car,new_partition,current_cmd);
+ }
+ else if((CHS2offset(disk_car,&end)>new_partition->part_offset) &&
+ new_partition->part_offset>0 &&
+ new_partition->part_type_i386!=P_NO_OS)
+ {
+ 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;
+ }
+ if(test_structure_i386(list_part)==0)
+ { /* Check if the partition can be Logical, Bootable or Primary */
+ if(can_be_ext(disk_car,new_partition)!=0)
+ {
+ new_partition->status=STATUS_LOG;
+ if(test_structure_i386(new_list_part)==0)
+ return new_list_part;
+ }
+ new_partition->status=STATUS_PRIM_BOOT;
+ if(test_structure_i386(new_list_part)==0)
+ return new_list_part;
+ new_partition->status=STATUS_PRIM;
+ if(test_structure_i386(new_list_part)==0)
+ return new_list_part;
+ }
+ new_partition->status=STATUS_DELETED;
+ return new_list_part;
+ }
+ else
+ {
+ free(new_partition);
+ return list_part;
+ }
+ }
+}
+
+#ifdef HAVE_NCURSES
+static list_part_t *add_partition_i386_ncurses(disk_t *disk_car,list_part_t *list_part, const int verbose, char **current_cmd)
+{
+ int position=0;
+ CHS_t start,end;
+ partition_t *new_partition=partition_new(&arch_i386);
+ start.cylinder=0;
+ start.head=0;
+ start.sector=1;
+ end.cylinder=disk_car->CHS.cylinder;
+ end.head=disk_car->CHS.head;
+ end.sector=disk_car->CHS.sector;
+ {
+ int done = 0;
+ while (done==0) {
+ int command;
+ static struct MenuItem menuGeometry[]=
+ {
+ { 'c', "Cylinder", "Change starting cylinder" },
+ { 'h', "Head", "Change starting head" },
+ { 's', "Sector", "Change starting sector" },
+ { 'C', "Cylinder", "Change ending cylinder" },
+ { 'H', "Head", "Change ending head" },
+ { 'S', "Sector", "Change ending sector" },
+ { 'T' ,"Type", "Change partition type"},
+ { 'd', "Done", "" },
+ { 0, NULL, NULL }
+ };
+ aff_copy(stdscr);
+ wmove(stdscr,4,0);
+ wdoprintf(stdscr,"%s",disk_car->description(disk_car));
+ new_partition->part_offset=CHS2offset(disk_car,&start);
+ new_partition->part_size=CHS2offset(disk_car,&end) - new_partition->part_offset + disk_car->sector_size;
+ wmove(stdscr,10, 0);
+ wclrtoeol(stdscr);
+ aff_part(stdscr,AFF_PART_SHORT,disk_car,new_partition);
+ wmove(stdscr,INTER_GEOM_Y, INTER_GEOM_X);
+ wclrtoeol(stdscr);
+ wrefresh(stdscr);
+ command=wmenuSimple(stdscr,menuGeometry, position);
+ switch (command) {
+ case 'c':
+ wmove(stdscr, INTER_GEOM_Y, INTER_GEOM_X);
+ start.cylinder=ask_number(start.cylinder,0,disk_car->CHS.cylinder,"Enter the starting cylinder ");
+ position=1;
+ break;
+ case 'h':
+ wmove(stdscr, INTER_GEOM_Y, INTER_GEOM_X);
+ start.head=ask_number(start.head,0,disk_car->CHS.head,"Enter the starting head ");
+ position=2;
+ break;
+ case 's':
+ wmove(stdscr, INTER_GEOM_Y, INTER_GEOM_X);
+ start.sector=ask_number(start.sector,1,disk_car->CHS.sector,"Enter the starting sector ");
+ position=3;
+ break;
+ case 'C':
+ wmove(stdscr, INTER_GEOM_Y, INTER_GEOM_X);
+ end.cylinder=ask_number(end.cylinder,start.cylinder,disk_car->CHS.cylinder,"Enter the ending cylinder ");
+ position=4;
+ break;
+ case 'H':
+ wmove(stdscr, INTER_GEOM_Y, INTER_GEOM_X);
+ end.head=ask_number(end.head,0,disk_car->CHS.head,"Enter the ending head ");
+ position=5;
+ break;
+ case 'S':
+ wmove(stdscr, INTER_GEOM_Y, INTER_GEOM_X);
+ end.sector=ask_number(end.sector,1,disk_car->CHS.sector,"Enter the ending sector ");
+ position=6;
+ break;
+ case 'T':
+ case 't':
+ change_part_type(disk_car,new_partition,current_cmd);
+ position=7;
+ break;
+ case key_ESC:
+ case 'd':
+ case 'D':
+ case 'q':
+ case 'Q':
+ done = 1;
+ break;
+ }
+ }
+ }
+ if((CHS2offset(disk_car,&end)>new_partition->part_offset)&&(new_partition->part_offset>0)&& new_partition->part_type_i386!=P_NO_OS)
+ {
+ 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;
+ }
+ if(test_structure_i386(list_part)==0)
+ { /* Check if the partition can be Logical, Bootable or Primary */
+ if(can_be_ext(disk_car,new_partition)!=0)
+ {
+ new_partition->status=STATUS_LOG;
+ if(test_structure_i386(new_list_part)==0)
+ return new_list_part;
+ }
+ new_partition->status=STATUS_PRIM_BOOT;
+ if(test_structure_i386(new_list_part)==0)
+ return new_list_part;
+ new_partition->status=STATUS_PRIM;
+ if(test_structure_i386(new_list_part)==0)
+ return new_list_part;
+ }
+ new_partition->status=STATUS_DELETED;
+ return new_list_part;
+ }
+ free(new_partition);
+ return list_part;
+}
+#endif
+
+static list_part_t *add_partition_i386(disk_t *disk_car,list_part_t *list_part, const int verbose, char **current_cmd)
+{
+ if(*current_cmd!=NULL)
+ return add_partition_i386_cli(disk_car, list_part, verbose, current_cmd);
+#ifdef HAVE_NCURSES
+ return add_partition_i386_ncurses(disk_car, list_part, verbose, current_cmd);
+#else
+ return list_part;
+#endif
+}
+
+static void set_next_status_i386(const disk_t *disk_car, partition_t *partition)
+{
+ if(partition->status==STATUS_LOG)
+ partition->status=STATUS_DELETED;
+ else
+ partition->status++;
+ if(partition->status==STATUS_LOG && can_be_ext(disk_car,partition)==0)
+ partition->status=STATUS_DELETED;
+}
+
+static void set_prev_status_i386(const disk_t *disk_car, partition_t *partition)
+{
+ if(partition->status==STATUS_DELETED)
+ partition->status=STATUS_LOG;
+ else
+ partition->status--;
+ if(partition->status==STATUS_LOG && can_be_ext(disk_car,partition)==0)
+ partition->status--;
+}
+
+static int set_part_type_i386(partition_t *partition, unsigned int part_type)
+{
+ if(part_type!=P_NO_OS && part_type <= 255 && is_extended(part_type)==0)
+ {
+ partition->part_type_i386=part_type;
+ return 0;
+ }
+ return 1;
+}
+
+static int is_part_known_i386(const partition_t *partition)
+{
+ return (partition->part_type_i386!=P_NO_OS && partition->part_type_i386!=P_UNK);
+}
+
+static void init_structure_i386(const disk_t *disk_car,list_part_t *list_part, const int verbose)
+{
+ /* Reconstruit une structure
+ * nbr_prim nombre de partition primaire
+ * end_log_block : partition etendu du block etendu
+ * nbr_log_block : nombre de block de partition etendu
+ * devrait etre 0 ou 1 */
+ unsigned int nbr_prim=0, nbr_log_block=0;
+ unsigned int vista_partition=0;
+ unsigned int log_block_size=0,biggest_log_block_size=0;
+ list_part_t *element;
+ list_part_t *end_log_block=NULL;
+ list_part_t *end_biggest_log_block=NULL;
+ 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;
+ if(element->part->arch!=NULL && element->part->arch!=disk_car->arch)
+ {
+ element->to_be_removed=1;
+ }
+ else
+ {
+ if(element->part->part_offset%(2048*512)==0 && element->part->part_size%(2048*512)==0)
+ vista_partition=1;
+ 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);
+ }
+ }
+ /* Verify */
+ for(element=new_list_part;element!=NULL;element=element->next)
+ {
+ if(can_be_ext(disk_car,element->part)==0)
+ {
+ nbr_prim++;
+ if((end_log_block!=NULL) && (end_log_block->next==element))
+ {
+ if(log_block_size>biggest_log_block_size)
+ {
+ biggest_log_block_size=log_block_size;
+ end_biggest_log_block=end_log_block;
+ }
+ nbr_log_block++;
+ end_log_block=NULL;
+ }
+ }
+ else
+ {
+ log_block_size++;
+ end_log_block=element;
+ }
+ }
+ /* Verification */
+ if((end_log_block!=NULL) && (end_log_block->next==NULL))
+ {
+ if(log_block_size>biggest_log_block_size)
+ {
+ biggest_log_block_size=log_block_size;
+ end_biggest_log_block=end_log_block;
+ }
+ nbr_log_block++;
+ }
+ if(verbose>1)
+ log_info("\nRes: nbr_prim %u, nbr_log_block %u, vista_partition=%u\n", nbr_prim, nbr_log_block, vista_partition);
+/* Set primary, extended, logical */
+ if(vista_partition==0 && nbr_prim+nbr_log_block<=4)
+ {
+ int set_prim_bootable_done=0;
+ for(element=end_biggest_log_block;element!=NULL && can_be_ext(disk_car,element->part);element=element->prev)
+ {
+ element->part->status=STATUS_LOG;
+ }
+ for(element=new_list_part;element!=NULL;element=element->next)
+ {
+ if(element->part->status!=STATUS_LOG)
+ {
+ /* The first primary partition is bootable unless it's a swap */
+ if(set_prim_bootable_done==0 &&
+ element->part->upart_type!=UP_LINSWAP && element->part->upart_type!=UP_LVM && element->part->upart_type!=UP_LVM2)
+ {
+ element->part->status=STATUS_PRIM_BOOT;
+ set_prim_bootable_done=1;
+ }
+ else
+ element->part->status=STATUS_PRIM;
+ }
+ }
+ }
+ if(vista_partition>0 || disk_car->arch->test_structure(new_list_part))
+ { /* Handle Vista partition */
+ unsigned int i;
+ int set_prim_bootable_done=0;
+ for(element=new_list_part,i=0;element!=NULL;element=element->next,i++)
+ {
+ if(i<3)
+ {
+ /* The first primary partition is bootable unless it's a swap */
+ if(set_prim_bootable_done==0 &&
+ element->part->upart_type!=UP_LINSWAP && element->part->upart_type!=UP_LVM && element->part->upart_type!=UP_LVM2)
+ {
+ element->part->status=STATUS_PRIM_BOOT;
+ set_prim_bootable_done=1;
+ }
+ else
+ element->part->status=STATUS_PRIM;
+ }
+ else
+ element->part->status=STATUS_LOG;
+ }
+ }
+#ifdef DEBUG
+ check_list_part(new_list_part);
+#endif
+ if(disk_car->arch->test_structure(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);
+#ifdef DEBUG
+ check_list_part(list_part);
+#endif
+}
+
+static int erase_list_part_i386(disk_t *disk_car)
+{
+ unsigned char buffer[DEFAULT_SECTOR_SIZE];
+ if(disk_car->read(disk_car,DEFAULT_SECTOR_SIZE, buffer, (uint64_t)0))
+ {
+ log_error(msg_PART_RD_ERR);
+ memset(buffer,0,sizeof(buffer));
+ }
+ memset(buffer+TAB_PART,0,0x40);
+ if(disk_car->write(disk_car,DEFAULT_SECTOR_SIZE, buffer, (uint64_t)0))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+static int check_part_i386(disk_t *disk_car,const int verbose,partition_t *partition, const int saveheader)
+{
+ int ret=0;
+ switch(partition->part_type_i386)
+ {
+ case P_BEOS:
+ ret=check_BeFS(disk_car,partition,verbose);
+ break;
+ case P_12FAT:
+ case P_16FAT:
+ case P_16FATBD:
+ case P_32FAT:
+ case P_32FAT_LBA:
+ case P_16FATBD_LBA:
+ case P_12FATH:
+ case P_16FATH:
+ case P_16FATBDH:
+ case P_32FATH:
+ case P_32FAT_LBAH:
+ case P_16FATBD_LBAH:
+ ret=check_FAT(disk_car,partition,verbose);
+ if(ret!=0)
+ { aff_buffer(BUFFER_ADD,"Invalid FAT boot sector\n"); }
+ break;
+ case P_FREEBSD:
+ ret=check_BSD(disk_car,partition,verbose,BSD_MAXPARTITIONS);
+ break;
+ case P_HFS:
+ ret=check_HFS(disk_car,partition,verbose);
+ if(ret!=0)
+ {
+ ret=check_HFSP(disk_car,partition,verbose);
+ }
+ break;
+ case P_LINUX:
+ ret=check_JFS(disk_car,partition,verbose);
+ if(ret!=0)
+ {
+ ret=check_rfs(disk_car,partition,verbose);
+ }
+ if(ret!=0)
+ {
+ ret=check_EXT2(disk_car,partition,verbose);
+ }
+ if(ret!=0)
+ {
+ ret=check_cramfs(disk_car,partition,verbose);
+ }
+ if(ret!=0)
+ {
+ ret=check_xfs(disk_car,partition,verbose);
+ }
+ if(ret!=0)
+ { aff_buffer(BUFFER_ADD,"No EXT2, JFS, Reiser, cramfs or XFS marker\n"); }
+ break;
+ case P_LINSWAP:
+ ret=check_Linux_SWAP(disk_car,partition,verbose);
+ break;
+ case P_LVM:
+ ret=check_LVM(disk_car,partition,verbose);
+ if(ret!=0)
+ {
+ ret=check_LVM2(disk_car,partition,verbose);
+ }
+ break;
+ case P_NETBSD:
+ ret=check_BSD(disk_car,partition,verbose,BSD_MAXPARTITIONS);
+ break;
+ case P_NTFS:
+ case P_NTFSH:
+ ret=check_NTFS(disk_car,partition,verbose,0);
+ if(ret!=0)
+ { aff_buffer(BUFFER_ADD,"Invalid NTFS boot\n"); }
+ break;
+ case P_OPENBSD:
+ ret=check_BSD(disk_car,partition,verbose,OPENBSD_MAXPARTITIONS);
+ break;
+ case P_RAID:
+ ret=check_MD(disk_car,partition,verbose);
+ if(ret!=0)
+ { aff_buffer(BUFFER_ADD,"Invalid RAID superblock\n"); }
+ break;
+ case P_SUN:
+ ret=check_sun_i386(disk_car,partition,verbose);
+ break;
+ case P_EXTENDED:
+ case P_EXTENDX:
+ case P_LINUXEXTENDX:
+ break;
+ case P_NETWARE:
+ /* res=check_netware(disk_car, partition, verbose); */
+ break;
+ default:
+ if(verbose>0)
+ {
+ log_warning("check_part_i386 %u type %02X: no test\n",partition->order,partition->part_type_i386);
+ }
+ if(saveheader>0)
+ {
+ save_header(disk_car,partition,verbose);
+ }
+ break;
+ }
+ if(ret!=0)
+ {
+ log_error("check_part_i386 failed for partition type %02X\n", partition->part_type_i386);
+ aff_part_buffer(AFF_PART_ORDER,disk_car,partition);
+ if(saveheader>0)
+ {
+ save_header(disk_car,partition,verbose);
+ }
+ }
+ return ret;
+}
+
+static const char *get_partition_typename_i386_aux(const unsigned int part_type_i386)
+{
+ int i;
+ for (i=0; i386_sys_types[i].name!=NULL; i++)
+ if (i386_sys_types[i].part_type == part_type_i386)
+ return i386_sys_types[i].name;
+ return NULL;
+}
+
+static const char *get_partition_typename_i386(const partition_t *partition)
+{
+ return get_partition_typename_i386_aux(partition->part_type_i386);
+}