OSDN Git Service

gpt: add partition attribute bits: NoBlockIOProtocol, LegacyBIOSBootable
[android-x86/external-parted.git] / libparted / labels / gpt.c
index cbaffa9..46e6077 100644 (file)
@@ -4,7 +4,7 @@
     original version by Matt Domsch <Matt_Domsch@dell.com>
     Disclaimed into the Public Domain
 
-    Portions Copyright (C) 2001-2003, 2005-2009 Free Software Foundation, Inc.
+    Portions Copyright (C) 2001-2003, 2005-2010 Free Software Foundation, Inc.
 
     EFI GUID Partition Table handling
     Per Intel EFI Specification v1.02
@@ -38,7 +38,9 @@
 #include <unistd.h>
 #include <uuid/uuid.h>
 #include <stdbool.h>
+#include <errno.h>
 #include "xalloc.h"
+#include "verify.h"
 
 #include "pt-tools.h"
 
@@ -68,6 +70,8 @@ typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
 typedef struct _PartitionRecord_t PartitionRecord_t;
 typedef struct _LegacyMBR_t LegacyMBR_t;
 typedef struct _GPTDiskData GPTDiskData;
+
+
 typedef struct
 {
   uint32_t time_low;
@@ -102,6 +106,10 @@ typedef struct
     ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
                     PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
                     { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
+#define PARTITION_MSFT_RECOVERY \
+    ((efi_guid_t) { PED_CPU_TO_LE32 (0xDE94BBA4), PED_CPU_TO_LE16 (0x06D1), \
+                    PED_CPU_TO_LE16 (0x4D40), 0xA1, 0x6A, \
+                    { 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC }})
 #define PARTITION_BASIC_DATA_GUID \
     ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
                     PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
@@ -130,6 +138,10 @@ typedef struct
     ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
                     PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
                     { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
+#define PARTITION_APPLE_TV_RECOVERY_GUID \
+    ((efi_guid_t) { PED_CPU_TO_LE32 (0x5265636F), PED_CPU_TO_LE16 (0x7665), \
+                    PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
+                    { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
 
 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
 {
@@ -154,12 +166,16 @@ struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
 {
 #ifdef __GNUC__                        /* XXX narrow this down to !TinyCC */
   uint64_t RequiredToFunction:1;
-  uint64_t Reserved:47;
+  uint64_t NoBlockIOProtocol:1;
+  uint64_t LegacyBIOSBootable:1;
+  uint64_t Reserved:45;
   uint64_t GuidSpecific:16;
 #else
 #       warning "Using crippled partition entry type"
   uint32_t RequiredToFunction:1;
-  uint32_t Reserved:32;
+  uint32_t NoBlockIOProtocol:1;
+  uint32_t LegacyBIOSBootable:1;
+  uint32_t Reserved:30;
   uint32_t LOST:5;
   uint32_t GuidSpecific:16;
 #endif
@@ -263,6 +279,8 @@ typedef struct _GPTPartitionData
   int hp_service;
   int hidden;
   int msftres;
+  int atvrecv;
+  int msftrecv;
 } GPTPartitionData;
 
 static PedDiskType gpt_disk_type;
@@ -335,12 +353,14 @@ pth_free (GuidPartitionTableHeader_t *pth)
 static uint8_t *
 pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
 {
-  uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
-  int size_static = pth_get_size_static (dev);
-
   PED_ASSERT (pth != NULL, return 0);
   PED_ASSERT (pth->Reserved2 != NULL, return 0);
 
+  int size_static = pth_get_size_static (dev);
+  uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
+  if (pth_raw == NULL)
+    return NULL;
+
   memcpy (pth_raw, pth, size_static);
   memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
 
@@ -388,20 +408,24 @@ efi_crc32 (const void *buf, unsigned long len)
   return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
 }
 
-static inline uint32_t
-pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
+/* Compute the crc32 checksum of the partition table header
+   and store it in *CRC32.  Return 0 upon success.  Return 1
+   upon failure to allocate space.  */
+static int
+pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth,
+           uint32_t *crc32)
 {
-  uint8_t *pth_raw = pth_get_raw (dev, pth);
-  uint32_t crc32 = 0;
-
   PED_ASSERT (dev != NULL, return 0);
   PED_ASSERT (pth != NULL, return 0);
 
-  crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
+  uint8_t *pth_raw = pth_get_raw (dev, pth);
+  if (pth_raw == NULL)
+    return 1;
 
+  *crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
   free (pth_raw);
 
-  return crc32;
+  return 0;
 }
 
 static inline int
@@ -432,11 +456,14 @@ static int
 gpt_probe (const PedDevice *dev)
 {
   GuidPartitionTableHeader_t *gpt = NULL;
-  uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
   int gpt_sig_found = 0;
 
   PED_ASSERT (dev != NULL, return 0);
 
+  if (dev->length <= 1)
+    return 0;
+
+  void *pth_raw = ped_malloc (pth_get_size (dev));
   if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
       || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
     {
@@ -447,8 +474,7 @@ gpt_probe (const PedDevice *dev)
 
   free (pth_raw);
 
-  if (gpt)
-    pth_free (gpt); // FIXME: now that pth_free works on NULL, remove the "if"
+  pth_free (gpt);
 
   if (!gpt_sig_found)
     return 0;
@@ -480,57 +506,6 @@ gpt_probe (const PedDevice *dev)
   return ok;
 }
 
-#ifndef DISCOVER_ONLY
-/* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
-static int
-gpt_clobber (PedDevice *dev)
-{
-  uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
-  GuidPartitionTableHeader_t *gpt;
-
-  PED_ASSERT (dev != NULL, return 0);
-
-  /*
-   * TO DISCUSS: check whether checksum is correct?
-   * If not, we might get a wrong AlternateLBA field and destroy
-   * one sector of random data.
-   */
-  if (!ped_device_read (dev, pth_raw,
-                        GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
-    {
-      free (pth_raw);
-      return 0;
-    }
-
-  gpt = pth_new_from_raw (dev, pth_raw);
-  free (pth_raw);
-
-  if (!ptt_clear_sectors (dev, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
-    goto error_free_with_gpt;
-  if (!ptt_clear_sectors (dev, GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
-    goto error_free_with_gpt;
-  if (!ptt_clear_sectors (dev, dev->length - GPT_HEADER_SECTORS,
-                          GPT_HEADER_SECTORS))
-    goto error_free_with_gpt;
-
-  if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1)
-    {
-      if (!ped_device_write (dev, gpt,
-                             PED_LE64_TO_CPU (gpt->AlternateLBA),
-                             GPT_HEADER_SECTORS))
-        return 0;
-    }
-
-  pth_free (gpt);
-
-  return 1;
-
-error_free_with_gpt:
-  pth_free (gpt);
-  return 0;
-}
-#endif /* !DISCOVER_ONLY */
-
 static PedDisk *
 gpt_alloc (const PedDevice *dev)
 {
@@ -591,11 +566,62 @@ gpt_free (PedDisk *disk)
   _ped_disk_free (disk);
 }
 
+/* Given GUID Partition table header, GPT, read its partition array
+   entries from DISK into malloc'd storage.  Set *PTES_BYTES to the
+   number of bytes required.  Upon success, return a pointer to the
+   resulting buffer.  Otherwise, set errno and return NULL.  */
+static void *
+gpt_read_PE_array (PedDisk const *disk, GuidPartitionTableHeader_t const *gpt,
+                   size_t *ptes_bytes)
+{
+  GPTDiskData *gpt_disk_data = disk->disk_specific;
+  uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
+  *ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
+  size_t ptes_sectors = ped_div_round_up (*ptes_bytes,
+                                          disk->dev->sector_size);
+
+  if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
+    {
+      errno = ENOMEM;
+      return NULL;
+    }
+  void *ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
+  if (ptes == NULL)
+    return NULL;
+
+  if (!ped_device_read (disk->dev, ptes,
+                        PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
+    {
+      int saved_errno = errno;
+      free (ptes);
+      errno = saved_errno;
+      return NULL;
+    }
+
+  return ptes;
+}
+
 static int
-_header_is_valid (const PedDevice *dev, GuidPartitionTableHeader_t *gpt,
+check_PE_array_CRC (PedDisk const *disk,
+                    GuidPartitionTableHeader_t const *gpt, bool *valid)
+{
+  size_t ptes_bytes;
+  void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
+  if (ptes == NULL)
+    return 1;
+
+  uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
+  *valid = (ptes_crc == PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32));
+  free (ptes);
+  return 0;
+}
+
+static int
+_header_is_valid (PedDisk const *disk, GuidPartitionTableHeader_t *gpt,
                   PedSector my_lba)
 {
   uint32_t crc, origcrc;
+  PedDevice const *dev = disk->dev;
 
   if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
     return 0;
@@ -629,16 +655,21 @@ _header_is_valid (const PedDevice *dev, GuidPartitionTableHeader_t *gpt,
   if (alt_lba == my_lba)
     return 0;
 
+  bool crc_match;
+  if (check_PE_array_CRC (disk, gpt, &crc_match) != 0 || !crc_match)
+    return 0;
+
   origcrc = gpt->HeaderCRC32;
   gpt->HeaderCRC32 = 0;
-  crc = pth_crc32 (dev, gpt);
+  if (pth_crc32 (dev, gpt, &crc) != 0)
+    return 0;
   gpt->HeaderCRC32 = origcrc;
 
   return crc == PED_LE32_TO_CPU (origcrc);
 }
 
 static int
-_parse_header (PedDisk *disk, GuidPartitionTableHeader_t *gpt,
+_parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
                int *update_needed)
 {
   GPTDiskData *gpt_disk_data = disk->disk_specific;
@@ -647,8 +678,6 @@ _parse_header (PedDisk *disk, GuidPartitionTableHeader_t *gpt,
   PedSector last_usable_if_grown, last_usable_min_default;
   static int asked_already;
 
-  // PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
-
 #ifndef DISCOVER_ONLY
   if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
     {
@@ -657,7 +686,7 @@ _parse_header (PedDisk *disk, GuidPartitionTableHeader_t *gpt,
            PED_EXCEPTION_IGNORE_CANCEL,
            _("The format of the GPT partition table is version "
              "%x, which is newer than what Parted can "
-             "recognise.  Please tell us!  bug-parted@gnu.org"),
+             "recognise.  Please report this!"),
            PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
         return 0;
     }
@@ -756,7 +785,8 @@ _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
   gpt_part_data->lvm = gpt_part_data->raid
     = gpt_part_data->boot = gpt_part_data->hp_service
     = gpt_part_data->hidden = gpt_part_data->msftres
-    = gpt_part_data->bios_grub = 0;
+    = gpt_part_data->msftrecv
+    = gpt_part_data->bios_grub = gpt_part_data->atvrecv = 0;
 
   if (pte->Attributes.RequiredToFunction & 0x1)
     gpt_part_data->hidden = 1;
@@ -773,6 +803,10 @@ _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
     gpt_part_data->hp_service = 1;
   else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
     gpt_part_data->msftres = 1;
+  else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RECOVERY))
+    gpt_part_data->msftrecv = 1;
+  else if (!guid_cmp (gpt_part_data->type, PARTITION_APPLE_TV_RECOVERY_GUID))
+    gpt_part_data->atvrecv = 1;
 
   return part;
 }
@@ -787,13 +821,14 @@ _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
    If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
    number in which it was found.  */
 static int
-gpt_read_headers (PedDevice *dev,
+gpt_read_headers (PedDisk const *disk,
                   GuidPartitionTableHeader_t **primary_gpt,
                   GuidPartitionTableHeader_t **backup_gpt,
                   PedSector *backup_sector_num_p)
 {
   *primary_gpt = NULL;
   *backup_gpt = NULL;
+  PedDevice const *dev = disk->dev;
 
   void *s1;
   if (!ptt_read_sector (dev, 1, &s1))
@@ -805,9 +840,11 @@ gpt_read_headers (PedDevice *dev,
     return 1;
   GuidPartitionTableHeader_t *pri = t;
 
-  bool valid_primary = _header_is_valid (dev, pri, 1);
+  bool valid_primary = _header_is_valid (disk, pri, 1);
   if (valid_primary)
     *primary_gpt = pri;
+  else
+    pth_free (pri);
 
   PedSector backup_sector_num =
     (valid_primary
@@ -818,15 +855,18 @@ gpt_read_headers (PedDevice *dev,
   if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
     return 1;
   t = pth_new_from_raw (dev, s_bak);
+  free (s_bak);
   if (t == NULL)
     return 1;
 
   GuidPartitionTableHeader_t *bak = t;
-  if (_header_is_valid (dev, bak, backup_sector_num))
+  if (_header_is_valid (disk, bak, backup_sector_num))
     {
       *backup_gpt = bak;
       *backup_sector_num_p = backup_sector_num;
     }
+  else
+    pth_free (bak);
 
   return 0;
 }
@@ -857,10 +897,9 @@ static int
 gpt_read (PedDisk *disk)
 {
   GPTDiskData *gpt_disk_data = disk->disk_specific;
-  void *ptes;
   int i;
 #ifndef DISCOVER_ONLY
-  int write_back = 1;
+  int write_back = 0;
 #endif
 
   ped_disk_delete_all (disk);
@@ -874,7 +913,7 @@ gpt_read (PedDisk *disk)
   GuidPartitionTableHeader_t *primary_gpt;
   GuidPartitionTableHeader_t *backup_gpt;
   PedSector backup_sector_num;
-  int read_failure = gpt_read_headers (disk->dev, &primary_gpt, &backup_gpt,
+  int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
                                        &backup_sector_num);
   if (read_failure)
     {
@@ -894,9 +933,9 @@ gpt_read (PedDisk *disk)
   if (primary_gpt && backup_gpt)
     {
       /* Both are valid.  */
+#ifndef DISCOVER_ONLY
       if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
         {
-#ifndef DISCOVER_ONLY
           switch (ped_exception_throw
                   (PED_EXCEPTION_ERROR,
                    (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
@@ -909,23 +948,15 @@ gpt_read (PedDisk *disk)
             case PED_EXCEPTION_CANCEL:
               goto error_free_gpt;
             case PED_EXCEPTION_FIX:
-              {
-                char *zeros = ped_malloc (pth_get_size (disk->dev));
-                memset (zeros, 0, disk->dev->sector_size);
-                ped_device_write (disk->dev, zeros,
-                                  PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
-                free (zeros);
-                /* FIXME: Replace the above with this:
-                   ptt_clear_sectors (disk-.dev,
-                       PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1); */
-              }
+              ptt_clear_sectors (disk->dev,
+                                 PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
+              write_back = 1;
               break;
             default:
-              write_back = 0;
               break;
             }
-#endif /* !DISCOVER_ONLY */
         }
+#endif /* !DISCOVER_ONLY */
       gpt = primary_gpt;
       pth_free (backup_gpt);
     }
@@ -969,22 +1000,13 @@ gpt_read (PedDisk *disk)
   if (!_parse_header (disk, gpt, &write_back))
     goto error_free_gpt;
 
-  uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
-  size_t ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
-  size_t ptes_sectors = ped_div_round_up (ptes_bytes,
-                                          disk->dev->sector_size);
-
-  if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
+  size_t ptes_bytes;
+  void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
+  if (ptes == NULL)
     goto error_free_gpt;
-  ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
-
-  if (!ped_device_read (disk->dev, ptes,
-                        PED_LE64_TO_CPU (gpt->PartitionEntryLBA),
-                        ptes_sectors))
-    goto error_free_ptes;
 
   uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
-  if (ptes_crc != gpt->PartitionEntryArrayCRC32)
+  if (ptes_crc != PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32))
     {
       ped_exception_throw
         (PED_EXCEPTION_ERROR,
@@ -993,12 +1015,12 @@ gpt_read (PedDisk *disk)
       goto error_free_ptes;
     }
 
+  uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
   for (i = 0; i < gpt_disk_data->entry_count; i++)
     {
       GuidPartitionEntry_t *pte
         = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
       PedPartition *part;
-      PedConstraint *constraint_exact;
 
       if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
         continue;
@@ -1010,9 +1032,10 @@ gpt_read (PedDisk *disk)
       part->fs_type = ped_file_system_probe (&part->geom);
       part->num = i + 1;
 
-      constraint_exact = ped_constraint_exact (&part->geom);
+      PedConstraint *constraint_exact = ped_constraint_exact (&part->geom);
       if (!ped_disk_add_partition (disk, part, constraint_exact))
         {
+          ped_constraint_destroy (constraint_exact);
           ped_partition_destroy (part);
           goto error_delete_all;
         }
@@ -1075,7 +1098,7 @@ _write_pmbr (PedDevice *dev)
   return write_ok;
 }
 
-static void
+static int
 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
                   GuidPartitionTableHeader_t **gpt_p)
 {
@@ -1118,7 +1141,13 @@ _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
     = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
   gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
   gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
-  gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
+
+  uint32_t crc;
+  if (pth_crc32 (disk->dev, gpt, &crc) != 0)
+    return 1;
+
+  gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
+  return 0;
 }
 
 static void
@@ -1180,10 +1209,14 @@ gpt_write (const PedDisk *disk)
     goto error_free_ptes;
 
   /* Write PTH and PTEs */
-  _generate_header (disk, 0, ptes_crc, &gpt);
+  /* FIXME: Caution: this code is nearly identical to what's just below. */
+  if (_generate_header (disk, 0, ptes_crc, &gpt) != 0)
+    goto error_free_ptes;
   pth_raw = pth_get_raw (disk->dev, gpt);
   pth_free (gpt);
-  bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
+  if (pth_raw == NULL)
+    goto error_free_ptes;
+  int write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
   free (pth_raw);
   if (!write_ok)
     goto error_free_ptes;
@@ -1192,9 +1225,13 @@ gpt_write (const PedDisk *disk)
     goto error_free_ptes;
 
   /* Write Alternate PTH & PTEs */
-  _generate_header (disk, 1, ptes_crc, &gpt);
+  /* FIXME: Caution: this code is nearly identical to what's just above. */
+  if (_generate_header (disk, 1, ptes_crc, &gpt) != 0)
+    goto error_free_ptes;
   pth_raw = pth_get_raw (disk->dev, gpt);
   pth_free (gpt);
+  if (pth_raw == NULL)
+    goto error_free_ptes;
   write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
   free (pth_raw);
   if (!write_ok)
@@ -1208,7 +1245,6 @@ gpt_write (const PedDisk *disk)
   free (ptes);
   return ped_device_sync (disk->dev);
 
-  free (pth_raw);
 error_free_ptes:
   free (ptes);
 error:
@@ -1270,6 +1306,8 @@ gpt_partition_new (const PedDisk *disk,
   gpt_part_data->hp_service = 0;
   gpt_part_data->hidden = 0;
   gpt_part_data->msftres = 0;
+  gpt_part_data->msftrecv = 0;
+  gpt_part_data->atvrecv = 0;
   uuid_generate ((unsigned char *) &gpt_part_data->uuid);
   swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
   memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
@@ -1365,6 +1403,16 @@ gpt_partition_set_system (PedPartition *part,
       gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
       return 1;
     }
+  if (gpt_part_data->msftrecv)
+    {
+      gpt_part_data->type = PARTITION_MSFT_RECOVERY;
+      return 1;
+    }
+  if (gpt_part_data->atvrecv)
+    {
+      gpt_part_data->type = PARTITION_APPLE_TV_RECOVERY_GUID;
+      return 1;
+    }
 
   if (fs_type)
     {
@@ -1462,7 +1510,10 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
         gpt_part_data->raid
           = gpt_part_data->lvm
           = gpt_part_data->bios_grub
-          = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
+          = gpt_part_data->hp_service
+          = gpt_part_data->msftres
+          = gpt_part_data->msftrecv
+          = gpt_part_data->atvrecv = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_BIOS_GRUB:
       gpt_part_data->bios_grub = state;
@@ -1470,7 +1521,10 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
         gpt_part_data->raid
           = gpt_part_data->lvm
           = gpt_part_data->boot
-          = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
+          = gpt_part_data->hp_service
+          = gpt_part_data->msftres
+          = gpt_part_data->msftrecv
+          = gpt_part_data->atvrecv = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_RAID:
       gpt_part_data->raid = state;
@@ -1478,7 +1532,10 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
         gpt_part_data->boot
           = gpt_part_data->lvm
           = gpt_part_data->bios_grub
-          = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
+          = gpt_part_data->hp_service
+          = gpt_part_data->msftres
+          = gpt_part_data->msftrecv
+          = gpt_part_data->atvrecv = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_LVM:
       gpt_part_data->lvm = state;
@@ -1486,7 +1543,10 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
         gpt_part_data->boot
           = gpt_part_data->raid
           = gpt_part_data->bios_grub
-          = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
+          = gpt_part_data->hp_service
+          = gpt_part_data->msftres
+          = gpt_part_data->msftrecv
+          = gpt_part_data->atvrecv = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_HPSERVICE:
       gpt_part_data->hp_service = state;
@@ -1494,7 +1554,10 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
         gpt_part_data->boot
           = gpt_part_data->raid
           = gpt_part_data->lvm
-          = gpt_part_data->bios_grub = gpt_part_data->msftres = 0;
+          = gpt_part_data->bios_grub
+          = gpt_part_data->msftres
+          = gpt_part_data->msftrecv
+          = gpt_part_data->atvrecv = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_MSFT_RESERVED:
       gpt_part_data->msftres = state;
@@ -1502,7 +1565,32 @@ gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
         gpt_part_data->boot
           = gpt_part_data->raid
           = gpt_part_data->lvm
-          = gpt_part_data->bios_grub = gpt_part_data->hp_service = 0;
+          = gpt_part_data->bios_grub
+          = gpt_part_data->hp_service
+          = gpt_part_data->msftrecv
+          = gpt_part_data->atvrecv = 0;
+      return gpt_partition_set_system (part, part->fs_type);
+    case PED_PARTITION_DIAG:
+      gpt_part_data->msftrecv = state;
+      if (state)
+        gpt_part_data->boot
+          = gpt_part_data->raid
+          = gpt_part_data->lvm
+          = gpt_part_data->bios_grub
+          = gpt_part_data->hp_service
+          = gpt_part_data->msftres
+          = gpt_part_data->atvrecv = 0;
+      return gpt_partition_set_system (part, part->fs_type);
+    case PED_PARTITION_APPLE_TV_RECOVERY:
+      gpt_part_data->atvrecv = state;
+      if (state)
+        gpt_part_data->boot
+          = gpt_part_data->raid
+          = gpt_part_data->lvm
+          = gpt_part_data->bios_grub
+          = gpt_part_data->hp_service
+          = gpt_part_data->msftres
+          = gpt_part_data->msftrecv = 0;
       return gpt_partition_set_system (part, part->fs_type);
     case PED_PARTITION_HIDDEN:
       gpt_part_data->hidden = state;
@@ -1537,6 +1625,10 @@ gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
       return gpt_part_data->hp_service;
     case PED_PARTITION_MSFT_RESERVED:
       return gpt_part_data->msftres;
+    case PED_PARTITION_DIAG:
+      return gpt_part_data->msftrecv;
+    case PED_PARTITION_APPLE_TV_RECOVERY:
+      return gpt_part_data->atvrecv;
     case PED_PARTITION_HIDDEN:
       return gpt_part_data->hidden;
     case PED_PARTITION_SWAP:
@@ -1560,6 +1652,8 @@ gpt_partition_is_flag_available (const PedPartition *part,
     case PED_PARTITION_BIOS_GRUB:
     case PED_PARTITION_HPSERVICE:
     case PED_PARTITION_MSFT_RESERVED:
+    case PED_PARTITION_DIAG:
+    case PED_PARTITION_APPLE_TV_RECOVERY:
     case PED_PARTITION_HIDDEN:
       return 1;
     case PED_PARTITION_SWAP:
@@ -1665,42 +1759,18 @@ gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
   return 0;
 }
 
-static bool
-gpt_partition_check (const PedPartition *part)
-{
-  return true;
-}
-
-#ifdef DISCOVER_ONLY
-# define NULL_IF_DISCOVER_ONLY(val) NULL
-#else
-# define NULL_IF_DISCOVER_ONLY(val) val
-#endif
+#include "pt-common.h"
+PT_define_limit_functions (gpt)
 
 static PedDiskOps gpt_disk_ops =
 {
-  probe:                       gpt_probe,
-  clobber:                     NULL_IF_DISCOVER_ONLY (gpt_clobber),
-  alloc:                       gpt_alloc,
-  duplicate:                   gpt_duplicate,
-  free:                                gpt_free,
-  read:                                gpt_read,
+  clobber:                     NULL,
   write:                       NULL_IF_DISCOVER_ONLY (gpt_write),
-  partition_new:               gpt_partition_new,
-  partition_duplicate:         gpt_partition_duplicate,
-  partition_destroy:           gpt_partition_destroy,
-  partition_set_system:                gpt_partition_set_system,
-  partition_set_flag:          gpt_partition_set_flag,
-  partition_get_flag:          gpt_partition_get_flag,
-  partition_is_flag_available: gpt_partition_is_flag_available,
+
   partition_set_name:          gpt_partition_set_name,
   partition_get_name:          gpt_partition_get_name,
-  partition_align:             gpt_partition_align,
-  partition_enumerate:         gpt_partition_enumerate,
-  partition_check:             gpt_partition_check,
-  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
+
+  PT_op_function_initializers (gpt)
 };
 
 static PedDiskType gpt_disk_type =
@@ -1714,9 +1784,6 @@ static PedDiskType gpt_disk_type =
 void
 ped_disk_gpt_init ()
 {
-  PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
-  PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
-
   ped_disk_type_register (&gpt_disk_type);
 }
 
@@ -1725,3 +1792,6 @@ ped_disk_gpt_done ()
 {
   ped_disk_type_unregister (&gpt_disk_type);
 }
+
+verify (sizeof (GuidPartitionEntryAttributes_t) == 8);
+verify (sizeof (GuidPartitionEntry_t) == 128);