File parted-gpt-mbr-sync.patch of Package parted

Index: libparted/labels/gpt.c
===================================================================
--- libparted/labels/gpt.c.orig	2009-07-23 19:52:08.000000000 +0200
+++ libparted/labels/gpt.c	2009-07-29 14:36:56.000000000 +0200
@@ -47,6 +47,11 @@
 #  define _(String) (String)
 #endif				/* ENABLE_NLS */
 
+/* IA64 always has a properly working EFI implementation */
+#ifndef __ia64__
+#define GPT_SYNC_MBR
+#endif
+
 #define EFI_PMBR_OSTYPE_EFI 0xEE
 #define MSDOS_MBR_SIGNATURE 0xaa55
 
@@ -968,13 +973,62 @@ error:
 	return 0;
 }
 
+#ifdef GPT_SYNC_MBR
+static inline unsigned char
+_part_to_ostype (PedPartition* part)
+{
+	GPTPartitionData* gpt_part_data = part->disk_specific;
+	if (part->fs_type) {
+		if (strncmp (part->fs_type->name, "fat", 3) == 0) return 0xc;
+		if (strncmp (part->fs_type->name, "ntfs", 4) == 0) return 0x7;
+		if (strncmp (part->fs_type->name, "hfs", 3) == 0) return 0xaf;
+		if (strstr (part->fs_type->name, "swap")) return 0x82;
+	}
+	return 0x83; // Everything else is Linux
+}
+
+static inline PedPartition*
+_find_first_part (const PedDisk* disk)
+{
+	PedPartition *retval = NULL, *part = NULL;
+	uint64_t lowest_end = 0xffffffffffffffff;
+	while (part = ped_disk_next_partition (disk, part)) {
+		if (part->geom.start == 0 || part->type == PED_PARTITION_METADATA
+				|| part->type == PED_PARTITION_FREESPACE)
+			continue;
+		if (part->geom.end < lowest_end) {
+			retval = part;
+			lowest_end = part->geom.end;
+		}
+	}
+	return retval;
+}
+
+static inline uint32_t
+_part_32bitmax (uint64_t in)
+{
+	if (in > 0xFFFFFFFFULL) 
+		return 0xFFFFFFFF;
+	else
+		return (uint32_t)in;
+}
+#endif
+
+
+
 #ifndef DISCOVER_ONLY
 /* Write the protective MBR (to keep DOS happy) */
 static int
-_write_pmbr (PedDevice * dev)
+_write_pmbr (const PedDisk * disk)
 {
+	PedDevice * dev = disk->dev;
 	LegacyMBR_t pmbr;
 
+#ifdef GPT_SYNC_MBR
+	int i, pmbr_id, first_entry = 0, last_entry = 3;
+	PedPartition *part = NULL, *esp;
+#endif
+
 	/* The UEFI spec is not clear about what to do with the following
 	   elements of the Protective MBR (pmbr): BootCode (0-440B),
 	   UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
@@ -982,11 +1036,14 @@ _write_pmbr (PedDevice * dev)
 	if (ped_device_read (dev, &pmbr, 0, GPT_PMBR_SECTORS) < GPT_PMBR_SECTORS)
 		memset (&pmbr, 0, sizeof(pmbr));
 
+#ifndef GPT_SYNC_MBR
 	/* Zero out all the legacy partitions.
 	   There are 4 PartitionRecords.  */
 	memset (pmbr.PartitionRecord, 0, sizeof pmbr.PartitionRecord);
+#endif
 
 	pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
+#ifndef GPT_SYNC_MBR
 	pmbr.PartitionRecord[0].OSType      = EFI_PMBR_OSTYPE_EFI;
 	pmbr.PartitionRecord[0].StartSector = 1;
 	pmbr.PartitionRecord[0].EndHead     = 0xFE;
@@ -997,6 +1054,54 @@ _write_pmbr (PedDevice * dev)
 		pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
 	else
 		pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
+#else
+	/* Search for an EFI System Partition */
+	esp = _find_first_part(disk);
+	if (!esp || !esp->fs_type || strncmp (esp->fs_type->name, "fat", 3) != 0)
+		esp = NULL;
+
+	pmbr_id = 3;
+	if (esp) {
+		pmbr_id = 0;
+		first_entry = 1;
+		last_entry = 4;
+	}
+
+	/* Write a pseudo-PMBR so Linux is happy */
+	pmbr.PartitionRecord[pmbr_id].OSType      = EFI_PMBR_OSTYPE_EFI;
+	pmbr.PartitionRecord[pmbr_id].StartSector = 1;
+	pmbr.PartitionRecord[pmbr_id].EndHead     = 0xFE;
+	pmbr.PartitionRecord[pmbr_id].EndSector   = 0xFF;
+	pmbr.PartitionRecord[pmbr_id].EndTrack    = 0xFF;
+	pmbr.PartitionRecord[pmbr_id].StartingLBA = PED_CPU_TO_LE32(1);
+	pmbr.PartitionRecord[pmbr_id].SizeInLBA = 1;
+	if (esp)
+		pmbr.PartitionRecord[pmbr_id].SizeInLBA = esp->geom.end - 1;
+
+	/* sync the first 3 GPT entries to MBR primary partitions */
+	for (i=first_entry; i < last_entry; i++) {
+		part = ped_disk_next_partition (disk, part);
+		if (part == NULL)
+			break;
+		/* we might get a starting garbage partition */
+		if (part->geom.start == 0 || part->type == PED_PARTITION_METADATA || part->type == PED_PARTITION_FREESPACE || part == esp) {
+			i--;
+			continue;
+		}
+		pmbr.PartitionRecord[i].OSType      = _part_to_ostype(part);
+		pmbr.PartitionRecord[i].StartSector = 1;
+		pmbr.PartitionRecord[i].StartHead     = 0xFE;
+		pmbr.PartitionRecord[i].StartSector   = 0xFF;
+		pmbr.PartitionRecord[i].StartTrack    = 0xFF;
+		pmbr.PartitionRecord[i].EndHead     = 0xFE;
+		pmbr.PartitionRecord[i].EndSector   = 0xFF;
+		pmbr.PartitionRecord[i].EndTrack    = 0xFF;
+		pmbr.PartitionRecord[i].StartingLBA = _part_32bitmax(part->geom.start);
+		if(((GPTPartitionData*)part->disk_specific)->boot)
+			pmbr.PartitionRecord[i].BootIndicator = 0x80;
+		pmbr.PartitionRecord[i].SizeInLBA = _part_32bitmax(part->geom.end - part->geom.start);
+	}
+#endif
 
 	return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
 }
@@ -1100,7 +1205,7 @@ gpt_write(const PedDisk * disk)
 	ptes_crc = efi_crc32 (ptes, ptes_size);
 
 	/* Write protective MBR */
-	if (!_write_pmbr (disk->dev))
+	if (!_write_pmbr (disk))
 		goto error_free_ptes;
 
 	/* Write PTH and PTEs */
openSUSE Build Service is sponsored by