--- parted-1.4.19-pre4/include/parted/disk_gpt.h.orig	Thu Sep 27 14:01:11 2001
+++ parted-1.4.19-pre4/include/parted/disk_gpt.h	Thu Sep 27 14:01:21 2001
@@ -32,13 +32,13 @@
 #define EFI_PMBR_OSTYPE_EFI 0xEF
 #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
 #define MSDOS_MBR_SIGNATURE 0xaa55
-#define GUID_PT_BLOCK_SIZE 512
+#define GPT_BLOCK_SIZE 512
 
 
-#define GUID_PT_HEADER_SIGNATURE 0x5452415020494645
-#define GUID_PT_HEADER_REVISION_V1_02 0x00010200
-#define GUID_PT_HEADER_REVISION_V1_00 0x00010000
-#define GUID_PT_HEADER_REVISION_V0_99 0x00009900
+#define GPT_HEADER_SIGNATURE 0x5452415020494645
+#define GPT_HEADER_REVISION_V1_02 0x00010200
+#define GPT_HEADER_REVISION_V1_00 0x00010000
+#define GPT_HEADER_REVISION_V0_99 0x00009900
 
 typedef uint16_t efi_char16_t;	/* UNICODE character */
 
@@ -86,7 +86,7 @@
 	uint32_t NumberOfPartitionEntries;
 	uint32_t SizeOfPartitionEntry;
 	uint32_t PartitionEntryArrayCRC32;
-	uint8_t Reserved2[GUID_PT_BLOCK_SIZE - 92];
+	uint8_t Reserved2[GPT_BLOCK_SIZE - 92];
 } __attribute__ ((packed)) GuidPartitionTableHeader_t;
 
 typedef struct _GuidPartitionEntryAttributes_t {
--- parted-1.4.19-pre4/libparted/disk_gpt.c.orig	Thu Sep 27 13:56:49 2001
+++ parted-1.4.19-pre4/libparted/disk_gpt.c	Fri Sep 28 15:33:20 2001
@@ -178,9 +178,20 @@
 
 
 static inline int
-is_legacy_mbr_valid(LegacyMBR_t * mbr)
+is_pmbr_valid(LegacyMBR_t * mbr)
 {
-	return (mbr ? (mbr->Signature == MSDOS_MBR_SIGNATURE) : 0);
+        int i, found = 0, signature = 0;
+        PED_ASSERT(mbr != NULL, return 0);
+	signature = (mbr->Signature == MSDOS_MBR_SIGNATURE);
+        for (i=0; signature && i<4; i++) {
+                if (mbr->PartitionRecord[i].OSType ==
+                    EFI_PMBR_OSTYPE_EFI_GPT) {
+                        found = 1;
+                        break;
+                }
+        }
+        if (signature && found) return 1;
+        return 0;
 }
 
 static inline int
@@ -502,10 +513,10 @@
 	if (!(*gpt = gpt_read_header(dev, lba)))
 		return rc;
 	/* Check the GUID Partition Table Signature */
-	if ((*gpt)->Signature != GUID_PT_HEADER_SIGNATURE) {
+	if ((*gpt)->Signature != GPT_HEADER_SIGNATURE) {
                 /* 
                 printf("GUID Partition Table Header Signature is wrong: %llx != %llx\n",
-			(*gpt)->Signature, GUID_PT_HEADER_SIGNATURE);
+			(*gpt)->Signature, GPT_HEADER_SIGNATURE);
                 */
 		ped_free(*gpt);
 		*gpt = NULL;
@@ -628,8 +639,8 @@
 
         // printf("in CreateNewGuidPartitionTableHeader()\n");
 	memset(&gpt, 0, sizeof(gpt));
-	gpt.Signature = GUID_PT_HEADER_SIGNATURE;
-	gpt.Revision = GUID_PT_HEADER_REVISION_V1_02;
+	gpt.Signature = GPT_HEADER_SIGNATURE;
+	gpt.Revision = GPT_HEADER_REVISION_V1_02;
 	gpt.HeaderSize = 92; /* per 1.02 spec */
 	gpt.MyLBA = 1;
 	gpt.AlternateLBA = last_lba(dev);
@@ -714,7 +725,7 @@
         PED_ASSERT(goodgpt != NULL, return 0);
         PED_ASSERT(ptes != NULL, return 0);
 
-        printf("GPT: Fixing broken header.\n");
+        // printf("GPT: Fixing broken header.\n");
 
 	*badgpt = (GuidPartitionTableHeader_t *)
                 ped_malloc(sizeof(GuidPartitionTableHeader_t));
@@ -768,10 +779,6 @@
 	int i;
 	if (!mbr)
 		return;
-	if (!is_legacy_mbr_valid(mbr)) {
-		printf("MBR is invalid.\n");
-		return;
-	}
 
 	printf("UniqueMBRSignature: %x\n", mbr->UniqueMBRSignature);
 	for (i = 0; i < 4; i++)
@@ -780,6 +787,124 @@
 	return;
 }
 
+static void
+erase_gpt(PedDevice * dev, GuidPartitionTableHeader_t * gpt,
+          GuidPartitionEntry_t * ptes)
+{
+        uint64_t header_lba;
+        PED_ASSERT(dev  != NULL, return);
+        if (gpt == NULL || ptes == NULL) return;
+
+        header_lba = gpt->MyLBA;
+        memset(ptes, 0,
+               gpt->NumberOfPartitionEntries *
+               gpt->SizeOfPartitionEntry);
+        gpt_write_part_entries(dev, gpt, ptes);
+        memset(gpt, 0, sizeof(*gpt));
+        ped_device_write(dev, gpt, header_lba, GPT_HEADER_SECTORS);
+}
+
+/**************************************************
+ * bad_pmbr_handler()
+ *
+ * Requires: dev, good_pgpt, good_agpt
+ * Modifies: dev, pgpt, agpt, ptes
+ * Returns:  1 if disk is considered GPT, 0 otherwise
+ */
+
+
+static int
+bad_pmbr_handler(PedDevice * dev, int good_pgpt, int good_agpt,
+                 GuidPartitionTableHeader_t ** pgpt,
+                 GuidPartitionTableHeader_t ** agpt,
+                 GuidPartitionEntry_t * ptes)
+{
+        PedExceptionOption ex_status=0;
+
+        ped_exception_leave_all();
+
+        if (good_pgpt && good_agpt) {
+                ex_status = ped_exception_throw(PED_EXCEPTION_ERROR,
+                                                PED_EXCEPTION_YES +
+                                                PED_EXCEPTION_NO  +
+                                                PED_EXCEPTION_IGNORE,
+_("This disk contains a valid Primary and Alternate GUID Partition Table\n"
+  "but the Protective MBR is invalid.  This generally means that the disk\n"
+  "had GPT partitions on it, but then a legacy partition editing tool\n"
+  "was used to change the partition table stored in the MBR.\n\n"
+  "Which data is valid,  GPT or MBR?\n"
+  "Yes will assume that the GPT information is correct, and rewrite the PMBR.\n"
+  "No will assume that the MBR is correct, and erase the GPT information.\n"
+  "Ignore will assume that the MBR is correct, but not change the disk.\n"
+          ));
+        }  else if (!good_pgpt && good_agpt) {
+                ex_status = ped_exception_throw(PED_EXCEPTION_ERROR,
+                                                PED_EXCEPTION_YES +
+                                                PED_EXCEPTION_NO  +
+                                                PED_EXCEPTION_IGNORE,
+_("This disk contains a valid Alternate GUID Partition Table\n"
+  "but the Primary GPT and Protective MBR are invalid.\n"
+  "This generally means that the disk had GPT partitions on it,\n"
+  "but then a legacy partition editing tool was used to change\n"
+  "the partition table stored in the MBR.\n\n"
+  "Which data is valid,  GPT or MBR?\n"
+  "Yes will assume that the GPT information is correct, and\n"
+  "   will rewrite the PMBR and Primary GPT.\n"
+  "No will assume that the MBR is correct, and erase the GPT information.\n"
+  "Ignore will assume that the MBR is correct, but not change the disk.\n"
+        ));
+        } else if (good_pgpt && !good_agpt) {
+                ex_status = ped_exception_throw(PED_EXCEPTION_ERROR,
+                                                PED_EXCEPTION_YES +
+                                                PED_EXCEPTION_NO  +
+                                                PED_EXCEPTION_IGNORE,
+_("This disk contains a valid Primary GUID Partition Table\n"
+  "but the Alternate GPT and Protective MBR are invalid.\n"
+  "This generally means that the disk had GPT partitions on it,\n"
+  "but then a legacy partition editing tool was used to change\n"
+  "the partition table stored in the MBR.\n\n"
+  "Which data is valid,  GPT or MBR?\n"
+  "Yes will assume that the GPT information is correct, and\n"
+  "   will rewrite the PMBR and Alternate GPT.\n"
+  "No will assume that the MBR is correct, and erase the GPT information.\n"
+  "Ignore will assume that the MBR is correct, but not change the disk.\n"
+        ));
+        } else {
+                ped_exception_fetch_all();
+                return 1;
+        }
+
+        switch (ex_status) {
+        case PED_EXCEPTION_YES:
+                gpt_write_pmbr(dev);
+                if (good_pgpt && !good_agpt) {
+                        gpt_fix_broken_header(dev, agpt, *pgpt, ptes);
+                        gpt_write_header(dev, *agpt);
+                        gpt_write_part_entries(dev, *agpt, ptes);
+                }
+                else if (!good_pgpt && good_agpt) {
+                        gpt_fix_broken_header(dev, pgpt, *agpt, ptes);
+                        gpt_write_header(dev, *pgpt);
+                        gpt_write_part_entries(dev, *pgpt, ptes);
+                }
+                ped_exception_fetch_all();
+                return 1;
+                break;
+        case PED_EXCEPTION_NO:
+                if (good_pgpt) {
+                        erase_gpt(dev, *pgpt, ptes);
+                }
+                if (good_agpt) {
+                        erase_gpt(dev, *agpt, ptes);
+                }
+                break;
+        case PED_EXCEPTION_IGNORE:
+        default:
+                break;
+        }
+        ped_exception_fetch_all();
+        return 0;
+}
 
 
 /************************************************************
@@ -794,6 +919,29 @@
  * Returns:
  *   1 if valid
  *   0 on error
+ * Comments:
+ *  Intel is changing the EFI Spec. (after v1.02) to say that a
+ *  disk is considered to have a GPT label only if the GPT
+ *  structures are correct, and the MBR is actually a Protective
+ *  MBR (has one 0xEE type partition).
+ *  Problem occurs when a GPT-partitioned disk is then
+ *  edited with a legacy (non-GPT-aware) application, such as
+ *  fdisk (which doesn't generally erase the PGPT or AGPT).
+ *  How should such a disk get handled?  As a GPT disk (throwing
+ *  away the fdisk changes), or as an MSDOS disk (throwing away
+ *  the GPT information).  Previously, I've taken the GPT-is-right,
+ *  MBR is wrong, approach, to stay consistent with the EFI Spec.
+ *  Intel disagrees, saying the disk should then be treated
+ *  as having a msdos label, not a GPT label.  If this is true,
+ *  then what's the point of having an AGPT, since if the PGPT
+ *  is screwed up, likely the PMBR is too, and the PMBR becomes
+ *  a single point of failure.
+ *  So, in the Linux kernel, I'm going to test for PMBR, and
+ *  warn if it's not there, and treat the disk as MSDOS, with a note
+ *  for users to use Parted to "fix up" their disk if they
+ *  really want it to be considered GPT.
+ *  Hence, gpt_find_valid() needs to ask the user how to fix
+ *  this (which one to consider right).
  ************************************************************/
 static int
 gpt_find_valid(const PedDevice * dev,
@@ -801,52 +949,70 @@
                GuidPartitionTableHeader_t ** agpt,
                GuidPartitionEntry_t       ** ptes)
 {
-	int rc = 0;
+	int good_pgpt=0, good_agpt=0, good_pmbr=0;
 	GuidPartitionEntry_t *pptes = NULL, *aptes = NULL;
-	uint64_t lastlba;
+        LegacyMBR_t *legacyMbr = NULL;
+	uint64_t header_lba, ptes_lba;
 
         PED_ASSERT(dev  != NULL, return 0);
         PED_ASSERT(pgpt != NULL, return 0);
         PED_ASSERT(agpt != NULL, return 0);
         PED_ASSERT(ptes != NULL, return 0);
 
-	lastlba = last_lba(dev);
 	/* Check the Primary GPT */
-	rc = gpt_is_valid(dev, 1, pgpt, &pptes);
-	if (rc) {
+	good_pgpt = gpt_is_valid(dev, 1, pgpt, &pptes);
+	if (good_pgpt) {
 		/* Primary GPT is OK, check the alternate and warn if bad */
-		rc = gpt_is_valid(dev, (*pgpt)->AlternateLBA,
+		good_agpt = gpt_is_valid(dev, (*pgpt)->AlternateLBA,
                                   agpt, &aptes);
 
-		if (!rc) {
+		if (!good_agpt) {
                         *agpt = NULL;
                         printf("Alternate GPT is invalid, using primary GPT.\n");
 		}
 		if (aptes) ped_free(aptes);
 		*ptes = pptes;
-		return 1;
 	} /* if primary is valid */
 	else {
 		/* Primary GPT is bad, check the Alternate GPT */
                 *pgpt = NULL;
-		rc = gpt_is_valid(dev, lastlba,
+		good_agpt = gpt_is_valid(dev, last_lba(dev),
                                   agpt, &aptes);
-		if (rc) {
+		if (good_agpt) {
 			/* Primary is bad, alternate is good.
 			   Return values from the alternate and warn.
 			 */
-			printf
-			    ("Primary GPT is invalid, using alternate GPT.\n");
+			printf("Primary GPT is invalid, using alternate GPT.\n");
 			*ptes = aptes;
+		}
+	}
+        
+        /* Now test for valid PMBR */
+        /* This will be added to the EFI Spec. per Intel after v1.02. */
+        if (good_pgpt || good_agpt) {
+                legacyMbr = malloc(sizeof(*legacyMbr));
+                if (legacyMbr) {
+                        memset(legacyMbr, 0, sizeof(*legacyMbr));
+                        ped_device_read(dev, legacyMbr, 0, 1);
+                        good_pmbr = is_pmbr_valid(legacyMbr);
+                        ped_free(legacyMbr);
+                }
+                if (good_pmbr) return 1;
+                else {
+                        if (bad_pmbr_handler((PedDevice *) dev,
+                                             good_pgpt, good_agpt,
+                                             pgpt, agpt, *ptes))
 			return 1;
 		}
 	}
-	/* Both primary and alternate GPTs are bad.
+        
+/*
+ * Both primary and alternate GPTs are bad.
 	 * This isn't our disk, return 0.
 	 */
-        *pgpt = NULL;
-        *agpt = NULL;
-        *ptes = NULL;
+        if (*pgpt) {ped_free(*pgpt); *pgpt = NULL;}
+        if (*agpt) {ped_free(*agpt); *agpt = NULL;}
+        if (*ptes) {ped_free(*ptes); *ptes = NULL;}
 	return 0;
 }
 
