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

Index: parted-2.4/libparted/labels/gpt.c
===================================================================
--- parted-2.4.orig/libparted/labels/gpt.c
+++ parted-2.4/libparted/labels/gpt.c
@@ -51,11 +51,6 @@
 #  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
 
@@ -290,6 +285,7 @@ typedef struct _GPTPartitionData
 } GPTPartitionData;
 
 static PedDiskType gpt_disk_type;
+static PedDiskType gpt_sync_mbr_disk_type;
 
 static inline uint32_t
 pth_get_size (const PedDevice *dev)
@@ -458,8 +454,50 @@ _pmbr_is_valid (const LegacyMBR_t *mbr)
   return 0;
 }
 
+/* checks if device has a hybrid protective MBR partition table
+ *
+ * If the 1st partition has type 0xEE that spans the entire
+ * size of the disk from sector 1 to the last sector
+ * (or 2 TiB, whichever is smaller), we consider it 'normal' GPT.
+ * Otherwise it is synced GPT with hybridized pMBR.
+ */
+static inline int
+_has_hybrid_pmbr (const PedDevice *dev)
+{
+  int has_hybrid_pmbr = 1;
+
+  PED_ASSERT (dev != NULL);
+
+  void *label;
+  if (!ptt_read_sector (dev, 0, &label))
+    return 0;
+
+  LegacyMBR_t mbr;
+  memcpy(&mbr, label, sizeof(mbr));
+
+  if (mbr.Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE)) {
+    free(label);
+    return 0;
+  }
+
+  uint32_t efi_gpt_expected_size;
+  if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
+    efi_gpt_expected_size = 0xFFFFFFFF;
+  else
+    efi_gpt_expected_size = dev->length - 1UL;
+
+  if ((mbr.PartitionRecord[0].OSType == EFI_PMBR_OSTYPE_EFI) &&
+      (mbr.PartitionRecord[0].StartingLBA == PED_CPU_TO_LE32(1)) &&
+      (mbr.PartitionRecord[0].SizeInLBA == PED_CPU_TO_LE32(efi_gpt_expected_size)))
+        /* pMBR is not hybrid */
+        has_hybrid_pmbr = 0;
+
+  free(label);
+  return has_hybrid_pmbr;
+}
+
 static int
-gpt_probe (const PedDevice *dev)
+_gpt_probe_generic(const PedDevice *dev)
 {
   GuidPartitionTableHeader_t *gpt = NULL;
   int gpt_sig_found = 0;
@@ -512,6 +550,19 @@ gpt_probe (const PedDevice *dev)
   return ok;
 }
 
+static int
+gpt_probe (const PedDevice *dev)
+{
+  return _gpt_probe_generic(dev) && !_has_hybrid_pmbr(dev);
+}
+
+
+static int
+gpt_sync_mbr_probe (const PedDevice *dev)
+{
+  return _gpt_probe_generic(dev) && _has_hybrid_pmbr(dev);
+}
+
 static PedDisk *
 gpt_alloc (const PedDevice *dev)
 {
@@ -543,6 +594,36 @@ error:
 }
 
 static PedDisk *
+gpt_sync_mbr_alloc (const PedDevice *dev)
+{
+  PedDisk *disk;
+  GPTDiskData *gpt_disk_data;
+  PedSector data_start, data_end;
+
+  disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_sync_mbr_disk_type);
+  if (!disk)
+    goto error;
+  disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
+  if (!disk->disk_specific)
+    goto error_free_disk;
+
+  data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
+  data_end = dev->length - 2
+    - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
+  ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
+                     data_end - data_start + 1);
+  gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
+  uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
+  swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
+  return disk;
+
+error_free_disk:
+  free (disk);
+error:
+  return NULL;
+}
+
+static PedDisk *
 gpt_duplicate (const PedDisk *disk)
 {
   PedDisk *new_disk;
@@ -920,7 +1001,7 @@ gpt_read (PedDisk *disk)
 
   /* motivation: let the user decide about the pmbr... during
      ped_disk_probe(), they probably didn't get a choice... */
-  if (!gpt_probe (disk->dev))
+  if (!gpt_probe (disk->dev) && !gpt_sync_mbr_probe(disk->dev))
     goto error;
 
   GuidPartitionTableHeader_t *gpt = NULL;
@@ -1078,7 +1159,6 @@ error:
 }
 
 
-#ifdef GPT_SYNC_MBR
 static inline unsigned char
 _part_to_ostype (PedPartition* part)
 {
@@ -1116,7 +1196,6 @@ _part_32bitmax (uint64_t in)
     else
         return (uint32_t)in;
 }
-#endif
 
 
 #ifndef DISCOVER_ONLY
@@ -1126,10 +1205,11 @@ _write_pmbr (const PedDisk *disk)
 {
     PedDevice * dev = disk->dev;
 
-#ifdef GPT_SYNC_MBR
+    /* need sync GPT -> hybrid pMBR ? */
+    int sync_pmbr = !strcmp(disk->type->name, "gpt_sync_mbr") ? 1 : 0;
+
     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),
@@ -1140,13 +1220,12 @@ _write_pmbr (const PedDisk *disk)
     return 0;
   LegacyMBR_t *pmbr = s0;
 
-#ifndef GPT_SYNC_MBR
   /* Zero out the legacy partitions.  */
   memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
-#endif
 
   pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
-#ifndef GPT_SYNC_MBR
+
+  if (!sync_pmbr) {
   pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
   pmbr->PartitionRecord[0].StartSector = 1;
   pmbr->PartitionRecord[0].EndHead = 0xFE;
@@ -1157,7 +1236,7 @@ _write_pmbr (const PedDisk *disk)
     pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
   else
     pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
-#else
+  } 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)
@@ -1191,6 +1270,13 @@ _write_pmbr (const PedDisk *disk)
           i--;
           continue;
       }
+
+      /* partition can not be represented by dos label - don't sync it */
+      if (part->geom.start > 0xFFFFFFFF ||
+          (part->geom.end - part->geom.start + 1) > 0xFFFFFFFF) {
+          continue;
+      }
+
       pmbr->PartitionRecord[i].OSType      = _part_to_ostype(part);
       pmbr->PartitionRecord[i].StartHead     = 0xFE;
       pmbr->PartitionRecord[i].StartSector   = 0xFF;
@@ -1203,8 +1289,7 @@ _write_pmbr (const PedDisk *disk)
           pmbr->PartitionRecord[i].BootIndicator = 0x80;
       pmbr->PartitionRecord[i].SizeInLBA = _part_32bitmax(part->geom.end - part->geom.start + 1);
   }
-#endif
-
+  }
   int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
                                    GPT_PMBR_SECTORS);
   free (s0);
@@ -1902,6 +1987,38 @@ static PedDiskOps gpt_disk_ops =
   PT_op_function_initializers (gpt)
 };
 
+static PedDiskOps gpt_sync_mbr_disk_ops =
+{
+  clobber:                      NULL,
+  write:                        NULL_IF_DISCOVER_ONLY (gpt_write),
+
+  partition_set_name:           gpt_partition_set_name,
+  partition_get_name:           gpt_partition_get_name,
+
+  /* probe function redefined */
+  probe:                             gpt_sync_mbr_probe,
+  /* alloc function redefined */
+  alloc:                             gpt_sync_mbr_alloc,
+  duplicate:                         gpt_duplicate,
+  free:                              gpt_free,
+  read:                              gpt_read,
+  partition_new:                     gpt_partition_new,
+  partition_duplicate:               gpt_partition_duplicate,
+  partition_set_flag:                gpt_partition_set_flag,
+  partition_get_flag:                gpt_partition_get_flag,
+  partition_set_system:              gpt_partition_set_system,
+  partition_is_flag_available:       gpt_partition_is_flag_available,
+  partition_align:                   gpt_partition_align,
+  partition_destroy:                 gpt_partition_destroy,
+  partition_enumerate:               gpt_partition_enumerate,
+  alloc_metadata:                    gpt_alloc_metadata,
+  get_max_primary_partition_count:   gpt_get_max_primary_partition_count,
+  get_max_supported_partition_count: gpt_get_max_supported_partition_count,
+  partition_check:                   gpt_partition_check,
+  max_length:                        gpt_partition_max_length,
+  max_start_sector:                  gpt_partition_max_start_sector
+};
+
 static PedDiskType gpt_disk_type =
 {
   next:		NULL,
@@ -1910,16 +2027,26 @@ static PedDiskType gpt_disk_type =
   features:	PED_DISK_TYPE_PARTITION_NAME
 };
 
+static PedDiskType gpt_sync_mbr_disk_type =
+{
+  next:		NULL,
+  name:		"gpt_sync_mbr",
+  ops:		&gpt_sync_mbr_disk_ops,
+  features:	PED_DISK_TYPE_PARTITION_NAME
+};
+
 void
 ped_disk_gpt_init ()
 {
   ped_disk_type_register (&gpt_disk_type);
+  ped_disk_type_register (&gpt_sync_mbr_disk_type);
 }
 
 void
 ped_disk_gpt_done ()
 {
   ped_disk_type_unregister (&gpt_disk_type);
+  ped_disk_type_unregister (&gpt_sync_mbr_disk_type);
 }
 
 verify (sizeof (GuidPartitionEntryAttributes_t) == 8);
openSUSE Build Service is sponsored by