original version by Matt Domsch <Matt_Domsch@dell.com>
Disclaimed into the Public Domain
- Portions Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007, 2008
- 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
#include <fcntl.h>
#include <unistd.h>
#include <uuid/uuid.h>
+#include <stdbool.h>
+#include <errno.h>
+#include "xalloc.h"
+#include "verify.h"
+
+#include "pt-tools.h"
#if ENABLE_NLS
# include <libintl.h>
# define _(String) gettext (String)
#else
# define _(String) (String)
-#endif /* ENABLE_NLS */
+#endif /* ENABLE_NLS */
#define EFI_PMBR_OSTYPE_EFI 0xEE
#define MSDOS_MBR_SIGNATURE 0xaa55
typedef struct _PartitionRecord_t PartitionRecord_t;
typedef struct _LegacyMBR_t LegacyMBR_t;
typedef struct _GPTDiskData GPTDiskData;
-typedef struct {
- uint32_t time_low;
- uint16_t time_mid;
- uint16_t time_hi_and_version;
- uint8_t clock_seq_hi_and_reserved;
- uint8_t clock_seq_low;
- uint8_t node[6];
+
+
+typedef struct
+{
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_hi_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[6];
} /* __attribute__ ((packed)) */ efi_guid_t;
/* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
* in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
#define UNUSED_ENTRY_GUID \
((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
#define PARTITION_SYSTEM_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
- PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
- { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
+ PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
+ { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
#define PARTITION_BIOS_GRUB_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
- PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
- { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
+ PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
+ { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
#define LEGACY_MBR_PARTITION_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
- PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
- { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
+ PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
+ { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
#define PARTITION_MSFT_RESERVED_GUID \
((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 }})
+ 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, \
- { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
+ PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
+ { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
#define PARTITION_RAID_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
- PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
- { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
+ PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
+ { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
#define PARTITION_SWAP_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
- PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
- { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
+ PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
+ { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
#define PARTITION_LVM_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
- PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
- { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
+ PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
+ { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
#define PARTITION_RESERVED_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
- PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
- { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
+ PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
+ { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
#define PARTITION_HPSERVICE_GUID \
((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
- PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
- { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
+ PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
+ { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
#define PARTITION_APPLE_HFS_GUID \
((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 }})
-
-struct __attribute__ ((packed)) _GuidPartitionTableHeader_t {
- uint64_t Signature;
- uint32_t Revision;
- uint32_t HeaderSize;
- uint32_t HeaderCRC32;
- uint32_t Reserved1;
- uint64_t MyLBA;
- uint64_t AlternateLBA;
- uint64_t FirstUsableLBA;
- uint64_t LastUsableLBA;
- efi_guid_t DiskGUID;
- uint64_t PartitionEntryLBA;
- uint32_t NumberOfPartitionEntries;
- uint32_t SizeOfPartitionEntry;
- uint32_t PartitionEntryArrayCRC32;
- uint8_t* Reserved2;
+ 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
+{
+ uint64_t Signature;
+ uint32_t Revision;
+ uint32_t HeaderSize;
+ uint32_t HeaderCRC32;
+ uint32_t Reserved1;
+ uint64_t MyLBA;
+ uint64_t AlternateLBA;
+ uint64_t FirstUsableLBA;
+ uint64_t LastUsableLBA;
+ efi_guid_t DiskGUID;
+ uint64_t PartitionEntryLBA;
+ uint32_t NumberOfPartitionEntries;
+ uint32_t SizeOfPartitionEntry;
+ uint32_t PartitionEntryArrayCRC32;
+ uint8_t *Reserved2;
};
-struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t {
-#ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
- uint64_t RequiredToFunction:1;
- uint64_t Reserved:47;
- uint64_t GuidSpecific:16;
+struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
+{
+#ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
+ uint64_t RequiredToFunction:1;
+ 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 LOST:5;
- uint32_t GuidSpecific:16;
+ uint32_t RequiredToFunction:1;
+ uint32_t NoBlockIOProtocol:1;
+ uint32_t LegacyBIOSBootable:1;
+ uint32_t Reserved:30;
+ uint32_t LOST:5;
+ uint32_t GuidSpecific:16;
#endif
};
-struct __attribute__ ((packed)) _GuidPartitionEntry_t {
- efi_guid_t PartitionTypeGuid;
- efi_guid_t UniquePartitionGuid;
- uint64_t StartingLBA;
- uint64_t EndingLBA;
- GuidPartitionEntryAttributes_t Attributes;
- efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
+struct __attribute__ ((packed)) _GuidPartitionEntry_t
+{
+ efi_guid_t PartitionTypeGuid;
+ efi_guid_t UniquePartitionGuid;
+ uint64_t StartingLBA;
+ uint64_t EndingLBA;
+ GuidPartitionEntryAttributes_t Attributes;
+ efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
};
#define GPT_PMBR_LBA 0
#define GPT_PMBR_SECTORS 1
#define GPT_PRIMARY_HEADER_LBA 1
#define GPT_HEADER_SECTORS 1
-#define GPT_PRIMARY_PART_TABLE_LBA 2
+#define GPT_PRIMARY_PART_TABLE_LBA 2
-/*
+/*
These values are only defaults. The actual on-disk structures
may define different sizes, so use those unless creating a new GPT disk!
*/
(GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
sizeof(GuidPartitionEntry_t))
+struct __attribute__ ((packed)) _PartitionRecord_t
+{
+ /* Not used by EFI firmware. Set to 0x80 to indicate that this
+ is the bootable legacy partition. */
+ uint8_t BootIndicator;
-struct __attribute__ ((packed)) _PartitionRecord_t {
- /* Not used by EFI firmware. Set to 0x80 to indicate that this
- is the bootable legacy partition. */
- uint8_t BootIndicator;
-
- /* Start of partition in CHS address, not used by EFI firmware. */
- uint8_t StartHead;
+ /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t StartHead;
- /* Start of partition in CHS address, not used by EFI firmware. */
- uint8_t StartSector;
+ /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t StartSector;
- /* Start of partition in CHS address, not used by EFI firmware. */
- uint8_t StartTrack;
+ /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t StartTrack;
- /* OS type. A value of 0xEF defines an EFI system partition.
- Other values are reserved for legacy operating systems, and
- allocated independently of the EFI specification. */
- uint8_t OSType;
+ /* OS type. A value of 0xEF defines an EFI system partition.
+ Other values are reserved for legacy operating systems, and
+ allocated independently of the EFI specification. */
+ uint8_t OSType;
- /* End of partition in CHS address, not used by EFI firmware. */
- uint8_t EndHead;
+ /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t EndHead;
- /* End of partition in CHS address, not used by EFI firmware. */
- uint8_t EndSector;
+ /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t EndSector;
- /* End of partition in CHS address, not used by EFI firmware. */
- uint8_t EndTrack;
+ /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t EndTrack;
- /* Starting LBA address of the partition on the disk. Used by
- EFI firmware to define the start of the partition. */
- uint32_t StartingLBA;
+ /* Starting LBA address of the partition on the disk. Used by
+ EFI firmware to define the start of the partition. */
+ uint32_t StartingLBA;
- /* Size of partition in LBA. Used by EFI firmware to determine
- the size of the partition. */
- uint32_t SizeInLBA;
+ /* Size of partition in LBA. Used by EFI firmware to determine
+ the size of the partition. */
+ uint32_t SizeInLBA;
};
/* Protected Master Boot Record & Legacy MBR share same structure */
/* Needs to be packed because the u16s force misalignment. */
-struct __attribute__ ((packed)) _LegacyMBR_t {
- uint8_t BootCode[440];
- uint32_t UniqueMBRSignature;
- uint16_t Unknown;
- PartitionRecord_t PartitionRecord[4];
- uint16_t Signature;
+struct __attribute__ ((packed)) _LegacyMBR_t
+{
+ uint8_t BootCode[440];
+ uint32_t UniqueMBRSignature;
+ uint16_t Unknown;
+ PartitionRecord_t PartitionRecord[4];
+ uint16_t Signature;
};
/* uses libparted's disk_specific field in PedDisk, to store our info */
-struct __attribute__ ((packed)) _GPTDiskData {
- PedGeometry data_area;
- int entry_count;
- efi_guid_t uuid;
+struct __attribute__ ((packed)) _GPTDiskData
+{
+ PedGeometry data_area;
+ int entry_count;
+ efi_guid_t uuid;
};
/* uses libparted's disk_specific field in PedPartition, to store our info */
-typedef struct _GPTPartitionData {
- efi_guid_t type;
- efi_guid_t uuid;
- char name[37];
- int lvm;
- int raid;
- int boot;
- int bios_grub;
- int hp_service;
- int hidden;
- int msftres;
+typedef struct _GPTPartitionData
+{
+ efi_guid_t type;
+ efi_guid_t uuid;
+ char name[37];
+ int lvm;
+ int raid;
+ int boot;
+ int bios_grub;
+ int hp_service;
+ int hidden;
+ int msftres;
+ int atvrecv;
+ int msftrecv;
} GPTPartitionData;
static PedDiskType gpt_disk_type;
-
static inline uint32_t
-pth_get_size (const PedDevice* dev)
+pth_get_size (const PedDevice *dev)
{
- return GPT_HEADER_SECTORS * dev->sector_size;
+ return GPT_HEADER_SECTORS * dev->sector_size;
}
-
static inline uint32_t
-pth_get_size_static (const PedDevice* dev)
+pth_get_size_static (const PedDevice *dev)
{
- return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
+ return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
}
-
static inline uint32_t
-pth_get_size_rsv2 (const PedDevice* dev)
+pth_get_size_rsv2 (const PedDevice *dev)
{
- return pth_get_size(dev) - pth_get_size_static(dev);
+ return pth_get_size (dev) - pth_get_size_static (dev);
}
-
-static GuidPartitionTableHeader_t*
-pth_new (const PedDevice* dev)
+static GuidPartitionTableHeader_t *
+pth_new (const PedDevice *dev)
{
- GuidPartitionTableHeader_t* pth = ped_malloc (
- sizeof (GuidPartitionTableHeader_t)
- + sizeof (uint8_t));
-
- pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
+ GuidPartitionTableHeader_t *pth =
+ ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
- return pth;
-}
+ pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
+ return pth;
+}
-static GuidPartitionTableHeader_t*
-pth_new_zeroed (const PedDevice* dev)
+static GuidPartitionTableHeader_t *
+pth_new_zeroed (const PedDevice *dev)
{
- GuidPartitionTableHeader_t* pth = pth_new (dev);
-
- memset (pth, 0, pth_get_size_static (dev));
- memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
-
- return (pth);
+ GuidPartitionTableHeader_t *pth = pth_new (dev);
+
+ memset (pth, 0, pth_get_size_static (dev));
+ memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
+
+ return (pth);
}
-
-static GuidPartitionTableHeader_t*
-pth_new_from_raw (const PedDevice* dev, const uint8_t* pth_raw)
+static GuidPartitionTableHeader_t *
+pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
{
- GuidPartitionTableHeader_t* pth = pth_new (dev);
-
- PED_ASSERT (pth_raw != NULL, return 0);
-
- memcpy (pth, pth_raw, pth_get_size_static (dev));
- memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
- pth_get_size_rsv2 (dev));
-
- return pth;
+ GuidPartitionTableHeader_t *pth = pth_new (dev);
+
+ PED_ASSERT (pth_raw != NULL, return 0);
+
+ memcpy (pth, pth_raw, pth_get_size_static (dev));
+ memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
+ pth_get_size_rsv2 (dev));
+
+ return pth;
}
static void
-pth_free (GuidPartitionTableHeader_t* pth)
+pth_free (GuidPartitionTableHeader_t *pth)
{
- PED_ASSERT (pth != NULL, return);
- PED_ASSERT (pth->Reserved2 != NULL, return);
+ if (pth == NULL)
+ return;
+ PED_ASSERT (pth->Reserved2 != NULL, return);
- free (pth->Reserved2);
- free (pth);
+ free (pth->Reserved2);
+ free (pth);
}
-static uint8_t*
-pth_get_raw (const PedDevice* dev, const 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);
-
- memcpy (pth_raw, pth, size_static);
- memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
-
- return pth_raw;
-}
+ 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));
+
+ return pth_raw;
+}
/**
* swap_uuid_and_efi_guid() - converts between uuid formats
*
* There are two different representations for Globally Unique Identifiers
* (GUIDs or UUIDs).
- *
+ *
* The RFC specifies a UUID as a string of 16 bytes, essentially
* a big-endian array of char.
* Intel, in their EFI Specification, references the same RFC, but
* Blame Intel.
*/
static void
-swap_uuid_and_efi_guid(uuid_t uuid)
+swap_uuid_and_efi_guid (uuid_t uuid)
{
- efi_guid_t *guid = (efi_guid_t *)uuid;
+ efi_guid_t *guid = (efi_guid_t *) uuid;
- PED_ASSERT(uuid != NULL, return);
- guid->time_low = PED_SWAP32(guid->time_low);
- guid->time_mid = PED_SWAP16(guid->time_mid);
- guid->time_hi_and_version = PED_SWAP16(guid->time_hi_and_version);
+ PED_ASSERT (uuid != NULL, return);
+ guid->time_low = PED_SWAP32 (guid->time_low);
+ guid->time_mid = PED_SWAP16 (guid->time_mid);
+ guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
}
/* returns the EFI-style CRC32 value for buf
- * This function uses the crc32 function by Gary S. Brown,
+ * This function uses the crc32 function by Gary S. Brown,
* but seeds the function with ~0, and xor's with ~0 at the end.
*/
static inline uint32_t
-efi_crc32(const void *buf, unsigned long len)
+efi_crc32 (const void *buf, unsigned long len)
{
- return (__efi_crc32(buf, len, ~0L) ^ ~0L);
+ 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));
-
- free (pth_raw);
-
- return crc32;
+ PED_ASSERT (dev != NULL, return 0);
+ PED_ASSERT (pth != NULL, return 0);
+
+ 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 0;
}
static inline int
guid_cmp (efi_guid_t left, efi_guid_t right)
{
- return memcmp(&left, &right, sizeof(efi_guid_t));
+ return memcmp (&left, &right, sizeof (efi_guid_t));
}
/* checks if 'mbr' is a protective MBR partition table */
static inline int
-_pmbr_is_valid (const LegacyMBR_t* mbr)
+_pmbr_is_valid (const LegacyMBR_t *mbr)
{
- int i;
+ int i;
- PED_ASSERT(mbr != NULL, return 0);
+ PED_ASSERT (mbr != NULL, return 0);
- if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
- return 0;
- for (i = 0; i < 4; i++) {
- if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
- return 1;
- }
- return 0;
-}
-
-static int
-gpt_probe (const PedDevice * dev)
-{
- GuidPartitionTableHeader_t* gpt = NULL;
- uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
- LegacyMBR_t legacy_mbr;
- int gpt_sig_found = 0;
-
- PED_ASSERT (dev != NULL, return 0);
-
- if (ped_device_read(dev, pth_raw, 1, GPT_HEADER_SECTORS)
- || ped_device_read(dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS)) {
- gpt = pth_new_from_raw (dev, pth_raw);
- if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
- gpt_sig_found = 1;
- }
-
- free (pth_raw);
-
- if (gpt)
- pth_free (gpt);
-
-
- if (!gpt_sig_found)
- return 0;
-
- if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) {
- if (!_pmbr_is_valid (&legacy_mbr)) {
- int ex_status = ped_exception_throw (
- PED_EXCEPTION_WARNING,
- PED_EXCEPTION_YES_NO,
- _("%s contains GPT signatures, indicating that it has "
- "a GPT table. However, it does not have a valid "
- "fake msdos partition table, as it should. Perhaps "
- "it was corrupted -- possibly by a program that "
- "doesn't understand GPT partition tables. Or "
- "perhaps you deleted the GPT table, and are now "
- "using an msdos partition table. Is this a GPT "
- "partition table?"),
- dev->path);
- if (ex_status == PED_EXCEPTION_NO)
- return 0;
- }
- }
-
- return 1;
+ if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
+ return 0;
+ for (i = 0; i < 4; i++)
+ {
+ if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
+ return 1;
+ }
+ return 0;
}
-#ifndef DISCOVER_ONLY
-/* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
static int
-gpt_clobber(PedDevice * dev)
+gpt_probe (const PedDevice *dev)
{
- LegacyMBR_t pmbr;
- uint8_t* zeroed_pth_raw = ped_malloc (pth_get_size (dev));
- uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
- GuidPartitionTableHeader_t* gpt;
-
- PED_ASSERT (dev != NULL, return 0);
-
- memset(&pmbr, 0, sizeof(pmbr));
- memset(zeroed_pth_raw, 0, pth_get_size (dev));
-
- /*
- * 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))
- goto error_free;
-
- gpt = pth_new_from_raw (dev, pth_raw);
-
- if (!ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
- goto error_free_with_gpt;
- if (!ped_device_write(dev, &zeroed_pth_raw,
- GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
- goto error_free_with_gpt;
- if (!ped_device_write(dev, &zeroed_pth_raw, 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);
-error_free:
- free (pth_raw);
- free (zeroed_pth_raw);
- return 0;
+ GuidPartitionTableHeader_t *gpt = NULL;
+ 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))
+ {
+ gpt = pth_new_from_raw (dev, pth_raw);
+ if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
+ gpt_sig_found = 1;
+ }
+
+ free (pth_raw);
+
+ pth_free (gpt);
+
+ if (!gpt_sig_found)
+ return 0;
+
+ void *label;
+ if (!ptt_read_sector (dev, 0, &label))
+ return 0;
+
+ int ok = 1;
+ if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
+ {
+ int ex_status = ped_exception_throw
+ (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_YES_NO,
+ _("%s contains GPT signatures, indicating that it has "
+ "a GPT table. However, it does not have a valid "
+ "fake msdos partition table, as it should. Perhaps "
+ "it was corrupted -- possibly by a program that "
+ "doesn't understand GPT partition tables. Or "
+ "perhaps you deleted the GPT table, and are now "
+ "using an msdos partition table. Is this a GPT "
+ "partition table?"),
+ dev->path);
+ if (ex_status == PED_EXCEPTION_NO)
+ ok = 0;
+ }
+
+ free (label);
+ return ok;
}
-#endif /* !DISCOVER_ONLY */
static PedDisk *
-gpt_alloc (const PedDevice * dev)
+gpt_alloc (const PedDevice *dev)
{
- PedDisk* disk;
- GPTDiskData *gpt_disk_data;
- PedSector data_start, data_end;
-
- disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_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;
+ PedDisk *disk;
+ GPTDiskData *gpt_disk_data;
+ PedSector data_start, data_end;
+
+ disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_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);
+ free (disk);
error:
- return NULL;
+ return NULL;
}
-static PedDisk*
-gpt_duplicate (const PedDisk* disk)
+static PedDisk *
+gpt_duplicate (const PedDisk *disk)
{
- PedDisk* new_disk;
- GPTDiskData* new_disk_data;
- GPTDiskData* old_disk_data;
-
- new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
- if (!new_disk)
- return NULL;
-
- old_disk_data = disk->disk_specific;
- new_disk_data = new_disk->disk_specific;
-
- ped_geometry_init (&new_disk_data->data_area, disk->dev,
- old_disk_data->data_area.start,
- old_disk_data->data_area.length);
- new_disk_data->entry_count = old_disk_data->entry_count;
- new_disk_data->uuid = old_disk_data->uuid;
- return new_disk;
+ PedDisk *new_disk;
+ GPTDiskData *new_disk_data;
+ GPTDiskData *old_disk_data;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ old_disk_data = disk->disk_specific;
+ new_disk_data = new_disk->disk_specific;
+
+ ped_geometry_init (&new_disk_data->data_area, disk->dev,
+ old_disk_data->data_area.start,
+ old_disk_data->data_area.length);
+ new_disk_data->entry_count = old_disk_data->entry_count;
+ new_disk_data->uuid = old_disk_data->uuid;
+ return new_disk;
}
static void
-gpt_free(PedDisk * disk)
+gpt_free (PedDisk *disk)
{
- ped_disk_delete_all (disk);
- free (disk->disk_specific);
- _ped_disk_free (disk);
+ ped_disk_delete_all (disk);
+ free (disk->disk_specific);
+ _ped_disk_free (disk);
}
-static int
-_header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
+/* 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)
{
- uint32_t crc, origcrc;
-
- if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
- return 0;
- /*
- * "While the GUID Partition Table Header's size may increase
- * in the future it cannot span more than one block on the
- * device." EFI Specification, version 1.10, 11.2.2.1
- */
- if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
- || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
- return 0;
-
- origcrc = gpt->HeaderCRC32;
- gpt->HeaderCRC32 = 0;
- crc = pth_crc32 (dev, gpt);
- gpt->HeaderCRC32 = origcrc;
-
- return crc == PED_LE32_TO_CPU (origcrc);
+ 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
-_read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt,
- PedSector where)
+check_PE_array_CRC (PedDisk const *disk,
+ GuidPartitionTableHeader_t const *gpt, bool *valid)
{
- uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
-
- PED_ASSERT (dev != NULL, return 0);
-
- if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) {
- free (pth_raw);
- return 0;
- }
-
- *gpt = pth_new_from_raw (dev, pth_raw);
-
- free (pth_raw);
-
- if (_header_is_valid (dev, *gpt))
- return 1;
-
- pth_free (*gpt);
- return 0;
+ 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
-_parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt,
- int *update_needed)
-{
- GPTDiskData* gpt_disk_data = disk->disk_specific;
- PedSector first_usable;
- PedSector last_usable;
- PedSector last_usable_if_grown, last_usable_min_default;
- static int asked_already;
+_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;
+ /*
+ * "While the GUID Partition Table Header's size may increase
+ * in the future it cannot span more than one block on the
+ * device." EFI Specification, version 1.10, 11.2.2.1
+ */
+ if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
+ || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
+ return 0;
+
+ /* The SizeOfPartitionEntry must be a multiple of 8 and
+ no smaller than the size of the PartitionEntry structure.
+ We also require that be no larger than 1/16th of UINT32_MAX,
+ as an additional sanity check. */
+ uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
+ if (sope % 8 != 0
+ || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
+ return 0;
+
+ if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
+ return 0;
+
+ PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
+ /* The backup table's AlternateLBA must be 1. */
+ if (my_lba != 1 && alt_lba != 1)
+ return 0;
+
+ /* The alt_lba must never be the same as my_lba. */
+ 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;
+ if (pth_crc32 (dev, gpt, &crc) != 0)
+ return 0;
+ gpt->HeaderCRC32 = origcrc;
+
+ return crc == PED_LE32_TO_CPU (origcrc);
+}
- PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
+static int
+_parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
+ int *update_needed)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ PedSector first_usable;
+ PedSector last_usable;
+ PedSector last_usable_if_grown, last_usable_min_default;
+ static int asked_already;
#ifndef DISCOVER_ONLY
- if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02) {
- if (ped_exception_throw (
- PED_EXCEPTION_WARNING,
- 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"),
- PED_LE32_TO_CPU (gpt->Revision))
- != PED_EXCEPTION_IGNORE)
- return 0;
- }
+ if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
+ {
+ if (ped_exception_throw
+ (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The format of the GPT partition table is version "
+ "%x, which is newer than what Parted can "
+ "recognise. Please report this!"),
+ PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
+ return 0;
+ }
#endif
- first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
- last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
-
-
-/*
- Need to check whether the volume has grown, the LastUsableLBA is
- normally set to disk->dev->length - 2 - ptes_size (at least for parted
- created volumes), where ptes_size is the number of entries *
- size of each entry / sector size or 16k / sector size, whatever the greater.
- If the volume has grown, offer the user the chance to use the new
- space or continue with the current usable area. Only ask once per
- parted invocation.
-*/
-
- last_usable_if_grown
- = PED_CPU_TO_LE64 (disk->dev->length - 2 -
- ((PedSector)(PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries)) *
- (PedSector)(PED_LE32_TO_CPU(gpt->SizeOfPartitionEntry)) /
- disk->dev->sector_size));
-
- last_usable_min_default = disk->dev->length - 2 -
- GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
-
- if ( last_usable_if_grown > last_usable_min_default ) {
-
- last_usable_if_grown = last_usable_min_default;
- }
-
-
- PED_ASSERT (last_usable > first_usable, return 0);
- PED_ASSERT (last_usable <= disk->dev->length, return 0);
-
- PED_ASSERT (last_usable_if_grown > first_usable, return 0);
- PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
-
- if ( !asked_already && last_usable < last_usable_if_grown ) {
-
- PedExceptionOption q;
-
- q = ped_exception_throw (PED_EXCEPTION_WARNING,
- PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
- _("Not all of the space available to %s appears "
- "to be used, you can fix the GPT to use all of the "
- "space (an extra %llu blocks) or continue with the "
- "current setting? "), disk->dev->path,
- (uint64_t)(last_usable_if_grown - last_usable));
-
-
- if (q == PED_EXCEPTION_FIX) {
-
- last_usable = last_usable_if_grown;
- *update_needed = 1;
-
- }
- else if (q != PED_EXCEPTION_UNHANDLED ) {
-
- asked_already = 1;
- }
- }
+ first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
+ last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
+
+ /* Need to check whether the volume has grown, the LastUsableLBA is
+ normally set to disk->dev->length - 2 - ptes_size (at least for parted
+ created volumes), where ptes_size is the number of entries *
+ size of each entry / sector size or 16k / sector size, whatever the greater.
+ If the volume has grown, offer the user the chance to use the new
+ space or continue with the current usable area. Only ask once per
+ parted invocation. */
+
+ last_usable_if_grown
+ = (disk->dev->length - 2 -
+ ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
+ (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
+ disk->dev->sector_size));
+
+ last_usable_min_default = disk->dev->length - 2 -
+ GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
+
+ if (last_usable_if_grown > last_usable_min_default)
+ {
+ last_usable_if_grown = last_usable_min_default;
+ }
+
+ PED_ASSERT (last_usable > first_usable, return 0);
+ PED_ASSERT (last_usable <= disk->dev->length, return 0);
+
+ PED_ASSERT (last_usable_if_grown > first_usable, return 0);
+ PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
+
+ if (!asked_already && last_usable < last_usable_if_grown)
+ {
+
+ PedExceptionOption q;
+
+ q = ped_exception_throw
+ (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
+ _("Not all of the space available to %s appears "
+ "to be used, you can fix the GPT to use all of the "
+ "space (an extra %llu blocks) or continue with the "
+ "current setting? "), disk->dev->path,
+ (uint64_t) (last_usable_if_grown - last_usable));
+
+ if (q == PED_EXCEPTION_FIX)
+ {
+ last_usable = last_usable_if_grown;
+ *update_needed = 1;
+ }
+ else if (q != PED_EXCEPTION_UNHANDLED)
+ {
+ asked_already = 1;
+ }
+ }
- ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
- first_usable, last_usable - first_usable + 1);
+ ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
+ first_usable, last_usable - first_usable + 1);
+ gpt_disk_data->entry_count
+ = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
+ PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
+ PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
- gpt_disk_data->entry_count
- = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
- PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
- PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
+ gpt_disk_data->uuid = gpt->DiskGUID;
- gpt_disk_data->uuid = gpt->DiskGUID;
+ return 1;
+}
- return 1;
+static PedPartition *
+_parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
+{
+ PedPartition *part;
+ GPTPartitionData *gpt_part_data;
+ unsigned int i;
+
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
+ PED_LE64_TO_CPU (pte->StartingLBA),
+ PED_LE64_TO_CPU (pte->EndingLBA));
+ if (!part)
+ return NULL;
+
+ gpt_part_data = part->disk_specific;
+ gpt_part_data->type = pte->PartitionTypeGuid;
+ gpt_part_data->uuid = pte->UniquePartitionGuid;
+ for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
+ gpt_part_data->name[i] =
+ (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
+ gpt_part_data->name[i] = 0;
+
+ 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->msftrecv
+ = gpt_part_data->bios_grub = gpt_part_data->atvrecv = 0;
+
+ if (pte->Attributes.RequiredToFunction & 0x1)
+ gpt_part_data->hidden = 1;
+
+ if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
+ gpt_part_data->boot = 1;
+ else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
+ gpt_part_data->bios_grub = 1;
+ else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
+ gpt_part_data->raid = 1;
+ else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
+ gpt_part_data->lvm = 1;
+ else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
+ 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;
}
-static PedPartition*
-_parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte)
+/* Read the primary GPT at sector 1 of DEV.
+ Verify its CRC and that of its partition entry array.
+ If they are valid, read the backup GPT specified by AlternateLBA.
+ If not, read the backup GPT in the last sector of the disk.
+ Return 1 if any read fails.
+ Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
+ Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
+ 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 (PedDisk const *disk,
+ GuidPartitionTableHeader_t **primary_gpt,
+ GuidPartitionTableHeader_t **backup_gpt,
+ PedSector *backup_sector_num_p)
{
- PedPartition* part;
- GPTPartitionData* gpt_part_data;
- unsigned int i;
-
- part = ped_partition_new (disk, 0, NULL,
- PED_LE64_TO_CPU(pte->StartingLBA),
- PED_LE64_TO_CPU(pte->EndingLBA));
- if (!part)
- return NULL;
-
- gpt_part_data = part->disk_specific;
- gpt_part_data->type = pte->PartitionTypeGuid;
- gpt_part_data->uuid = pte->UniquePartitionGuid;
- for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
- gpt_part_data->name[i] = (efi_char16_t) PED_LE16_TO_CPU(
- (uint16_t) pte->PartitionName[i]);
- gpt_part_data->name[i] = 0;
-
- 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;
-
- if (pte->Attributes.RequiredToFunction & 0x1)
- gpt_part_data->hidden = 1;
-
- if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
- gpt_part_data->boot = 1;
- else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
- gpt_part_data->bios_grub = 1;
- else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
- gpt_part_data->raid = 1;
- else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
- gpt_part_data->lvm = 1;
- else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
- gpt_part_data->hp_service = 1;
- else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
- gpt_part_data->msftres = 1;
-
- return part;
+ *primary_gpt = NULL;
+ *backup_gpt = NULL;
+ PedDevice const *dev = disk->dev;
+
+ void *s1;
+ if (!ptt_read_sector (dev, 1, &s1))
+ return 1;
+
+ GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
+ free (s1);
+ if (t == NULL)
+ return 1;
+ GuidPartitionTableHeader_t *pri = t;
+
+ 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
+ ? PED_LE64_TO_CPU (pri->AlternateLBA)
+ : dev->length - 1);
+
+ void *s_bak;
+ 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 (disk, bak, backup_sector_num))
+ {
+ *backup_gpt = bak;
+ *backup_sector_num_p = backup_sector_num;
+ }
+ else
+ pth_free (bak);
+
+ return 0;
}
/************************************************************
* really want it to be considered GPT.
************************************************************/
static int
-gpt_read (PedDisk * disk)
+gpt_read (PedDisk *disk)
{
- GPTDiskData *gpt_disk_data = disk->disk_specific;
- GuidPartitionTableHeader_t* gpt;
- GuidPartitionEntry_t* ptes;
- int ptes_size;
- int i;
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ int i;
#ifndef DISCOVER_ONLY
- int write_back = 0;
+ int write_back = 0;
#endif
- ped_disk_delete_all (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))
- goto error;
-
- if (_read_header (disk->dev, &gpt, 1)) {
- PED_ASSERT ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
- <= disk->dev->length - 1, goto error_free_gpt);
- if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
- < disk->dev->length - 1) {
- char* zeros = ped_malloc (pth_get_size (disk->dev));
-
+ ped_disk_delete_all (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))
+ goto error;
+
+ GuidPartitionTableHeader_t *gpt = NULL;
+ GuidPartitionTableHeader_t *primary_gpt;
+ GuidPartitionTableHeader_t *backup_gpt;
+ PedSector backup_sector_num;
+ int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
+ &backup_sector_num);
+ if (read_failure)
+ {
+ /* This includes the case in which there used to be a GPT partition
+ table here, with an alternate LBA that extended beyond the current
+ end-of-device. It's treated as a non-match. */
+
+ /* Another possibility:
+ The primary header is ok, but backup is corrupt.
+ In the UEFI spec, this means the primary GUID table
+ is officially invalid. */
+ pth_free (backup_gpt);
+ pth_free (primary_gpt);
+ return 0;
+ }
+
+ if (primary_gpt && backup_gpt)
+ {
+ /* Both are valid. */
#ifndef DISCOVER_ONLY
- if (ped_exception_throw (
- PED_EXCEPTION_ERROR,
- PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
- _("The backup GPT table is not at the end of the disk, as it "
- "should be. This might mean that another operating system "
- "believes the disk is smaller. Fix, by moving the backup "
- "to the end (and removing the old backup)?"))
- == PED_EXCEPTION_CANCEL)
- goto error_free_gpt;
-
- write_back = 1;
- memset (zeros, 0, disk->dev->sector_size);
- ped_device_write (disk->dev, zeros,
- PED_LE64_TO_CPU (gpt->AlternateLBA),
- 1);
+ if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
+ {
+ switch (ped_exception_throw
+ (PED_EXCEPTION_ERROR,
+ (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
+ | PED_EXCEPTION_IGNORE),
+ _("The backup GPT table is not at the end of the disk, as it "
+ "should be. This might mean that another operating system "
+ "believes the disk is smaller. Fix, by moving the backup "
+ "to the end (and removing the old backup)?")))
+ {
+ case PED_EXCEPTION_CANCEL:
+ goto error_free_gpt;
+ case PED_EXCEPTION_FIX:
+ ptt_clear_sectors (disk->dev,
+ PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
+ write_back = 1;
+ break;
+ default:
+ break;
+ }
+ }
#endif /* !DISCOVER_ONLY */
- }
- } else { /* primary GPT *not* ok */
- int alternate_ok = 0;
-
-#ifndef DISCOVER_ONLY
- write_back = 1;
-#endif
-
- if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
- < disk->dev->length - 1) {
- alternate_ok = _read_header (disk->dev, &gpt,
- PED_LE64_TO_CPU(gpt->AlternateLBA));
- }
- if (!alternate_ok) {
- alternate_ok = _read_header (disk->dev, &gpt,
- disk->dev->length - 1);
- }
-
- if (alternate_ok) {
- if (ped_exception_throw (
- PED_EXCEPTION_ERROR,
- PED_EXCEPTION_OK_CANCEL,
- _("The primary GPT table is corrupt, but the "
- "backup appears OK, so that will be used."))
- == PED_EXCEPTION_CANCEL)
- goto error_free_gpt;
- } else {
- ped_exception_throw (
- PED_EXCEPTION_ERROR,
- PED_EXCEPTION_CANCEL,
- _("Both the primary and backup GPT tables "
- "are corrupt. Try making a fresh table, "
- "and using Parted's rescue feature to "
- "recover partitions."));
- goto error;
- }
- }
-
- if (!_parse_header (disk, gpt, &write_back))
- goto error_free_gpt;
-
-
- ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
- ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
- if (!ped_device_read (disk->dev, ptes,
- PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
- ptes_size / disk->dev->sector_size))
- goto error_free_ptes;
-
- for (i = 0; i < gpt_disk_data->entry_count; i++) {
- PedPartition* part;
- PedConstraint* constraint_exact;
-
- if (!guid_cmp (ptes[i].PartitionTypeGuid, UNUSED_ENTRY_GUID))
- continue;
-
- part = _parse_part_entry (disk, &ptes[i]);
- if (!part)
- goto error_delete_all;
-
- part->fs_type = ped_file_system_probe (&part->geom);
- part->num = i + 1;
-
- constraint_exact = ped_constraint_exact (&part->geom);
- if (!ped_disk_add_partition(disk, part, constraint_exact)) {
- ped_partition_destroy (part);
- goto error_delete_all;
- }
- ped_constraint_destroy (constraint_exact);
- }
- free (ptes);
+ gpt = primary_gpt;
+ pth_free (backup_gpt);
+ }
+ else if (!primary_gpt && !backup_gpt)
+ {
+ /* Both are corrupt. */
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Both the primary and backup GPT tables "
+ "are corrupt. Try making a fresh table, "
+ "and using Parted's rescue feature to "
+ "recover partitions."));
+ goto error;
+ }
+ else if (primary_gpt && !backup_gpt)
+ {
+ /* The primary header is ok, but backup is corrupt. */
+ if (ped_exception_throw
+ (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
+ _("The backup GPT table is corrupt, but the "
+ "primary appears OK, so that will be used."))
+ == PED_EXCEPTION_CANCEL)
+ goto error_free_gpt;
+
+ gpt = primary_gpt;
+ }
+ else /* !primary_gpt && backup_gpt */
+ {
+ /* primary GPT corrupt, backup is ok. */
+ if (ped_exception_throw
+ (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
+ _("The primary GPT table is corrupt, but the "
+ "backup appears OK, so that will be used."))
+ == PED_EXCEPTION_CANCEL)
+ goto error_free_gpt;
+
+ gpt = backup_gpt;
+ }
+ backup_gpt = NULL;
+ primary_gpt = NULL;
+
+ if (!_parse_header (disk, gpt, &write_back))
+ goto error_free_gpt;
+
+ size_t ptes_bytes;
+ void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
+ if (ptes == NULL)
+ goto error_free_gpt;
+
+ uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
+ if (ptes_crc != PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32))
+ {
+ ped_exception_throw
+ (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("primary partition table array CRC mismatch"));
+ 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;
+
+ if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
+ continue;
+
+ part = _parse_part_entry (disk, pte);
+ if (!part)
+ goto error_delete_all;
+
+ part->fs_type = ped_file_system_probe (&part->geom);
+ part->num = i + 1;
+
+ 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;
+ }
+ ped_constraint_destroy (constraint_exact);
+ }
+ free (ptes);
#ifndef DISCOVER_ONLY
- if (write_back)
- ped_disk_commit_to_dev (disk);
+ if (write_back)
+ ped_disk_commit_to_dev (disk);
#endif
- pth_free (gpt);
- return 1;
+ pth_free (gpt);
+ return 1;
error_delete_all:
- ped_disk_delete_all (disk);
+ ped_disk_delete_all (disk);
error_free_ptes:
- free (ptes);
+ free (ptes);
error_free_gpt:
- pth_free (gpt);
+ pth_free (primary_gpt);
+ pth_free (backup_gpt);
+ pth_free (gpt);
error:
- return 0;
+ return 0;
}
#ifndef DISCOVER_ONLY
-/* Writes the protective MBR (to keep DOS happy) */
+/* Write the protective MBR (to keep DOS happy) */
static int
-_write_pmbr (PedDevice * dev)
+_write_pmbr (PedDevice *dev)
{
- LegacyMBR_t pmbr;
-
- memset(&pmbr, 0, sizeof(pmbr));
- pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
- pmbr.PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
- pmbr.PartitionRecord[0].StartSector = 1;
- pmbr.PartitionRecord[0].EndHead = 0xFE;
- pmbr.PartitionRecord[0].EndSector = 0xFF;
- pmbr.PartitionRecord[0].EndTrack = 0xFF;
- pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
- if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
- pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
- else
- pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
-
- return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
+ /* 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).
+ With this in mind, we try not to modify these elements. */
+ void *s0;
+ if (!ptt_read_sector (dev, 0, &s0))
+ return 0;
+ LegacyMBR_t *pmbr = s0;
+
+ /* Zero out the legacy partitions. */
+ memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
+
+ pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
+ pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
+ pmbr->PartitionRecord[0].StartSector = 1;
+ pmbr->PartitionRecord[0].EndHead = 0xFE;
+ pmbr->PartitionRecord[0].EndSector = 0xFF;
+ pmbr->PartitionRecord[0].EndTrack = 0xFF;
+ pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
+ if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
+ pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
+ else
+ pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
+
+ int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
+ GPT_PMBR_SECTORS);
+ free (s0);
+ return write_ok;
}
-static void
-_generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
- GuidPartitionTableHeader_t** gpt_p)
+static int
+_generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
+ GuidPartitionTableHeader_t **gpt_p)
{
- GPTDiskData* gpt_disk_data = disk->disk_specific;
- GuidPartitionTableHeader_t* gpt;
-
- *gpt_p = pth_new_zeroed (disk->dev);
-
- gpt = *gpt_p;
-
- gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
- gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
-
- /* per 1.00 spec */
- gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
- gpt->HeaderCRC32 = 0;
- gpt->Reserved1 = 0;
-
- if (alternate) {
- PedSector ptes_size = gpt_disk_data->entry_count
- * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
-
- gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
- gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
- gpt->PartitionEntryLBA
- = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
- } else {
- gpt->MyLBA = PED_CPU_TO_LE64 (1);
- gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
- gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
- }
-
- gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
- gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
- gpt->DiskGUID = gpt_disk_data->uuid;
- gpt->NumberOfPartitionEntries
- = 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));
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ GuidPartitionTableHeader_t *gpt;
+
+ *gpt_p = pth_new_zeroed (disk->dev);
+
+ gpt = *gpt_p;
+
+ gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
+ gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
+
+ /* per 1.00 spec */
+ gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
+ gpt->HeaderCRC32 = 0;
+ gpt->Reserved1 = 0;
+
+ if (alternate)
+ {
+ PedSector ptes_size = gpt_disk_data->entry_count
+ * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
+
+ gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
+ gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
+ gpt->PartitionEntryLBA
+ = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
+ }
+ else
+ {
+ gpt->MyLBA = PED_CPU_TO_LE64 (1);
+ gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
+ gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
+ }
+
+ gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
+ gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
+ gpt->DiskGUID = gpt_disk_data->uuid;
+ gpt->NumberOfPartitionEntries
+ = 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);
+
+ uint32_t crc;
+ if (pth_crc32 (disk->dev, gpt, &crc) != 0)
+ return 1;
+
+ gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
+ return 0;
}
static void
-_partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
+_partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
{
- GPTPartitionData* gpt_part_data = part->disk_specific;
- unsigned int i;
-
- PED_ASSERT (gpt_part_data != NULL, return);
-
- pte->PartitionTypeGuid = gpt_part_data->type;
- pte->UniquePartitionGuid = gpt_part_data->uuid;
- pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
- pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
- memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
-
- if (gpt_part_data->hidden)
- pte->Attributes.RequiredToFunction = 1;
-
- for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
- pte->PartitionName[i]
- = (efi_char16_t) PED_CPU_TO_LE16(
- (uint16_t) gpt_part_data->name[i]);
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+ unsigned int i;
+
+ PED_ASSERT (gpt_part_data != NULL, return);
+
+ pte->PartitionTypeGuid = gpt_part_data->type;
+ pte->UniquePartitionGuid = gpt_part_data->uuid;
+ pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
+ pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
+ memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
+
+ if (gpt_part_data->hidden)
+ pte->Attributes.RequiredToFunction = 1;
+
+ for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
+ pte->PartitionName[i]
+ = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
}
static int
-gpt_write(const PedDisk * disk)
+gpt_write (const PedDisk *disk)
{
- GPTDiskData* gpt_disk_data;
- GuidPartitionEntry_t* ptes;
- uint32_t ptes_crc;
- uint8_t* pth_raw;
- GuidPartitionTableHeader_t* gpt;
- PedPartition* part;
- int ptes_size;
-
- PED_ASSERT (disk != NULL, goto error);
- PED_ASSERT (disk->dev != NULL, goto error);
- PED_ASSERT (disk->disk_specific != NULL, goto error);
-
- gpt_disk_data = disk->disk_specific;
-
- ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
- ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
- if (!ptes)
- goto error;
- memset (ptes, 0, ptes_size);
- for (part = ped_disk_next_partition (disk, NULL); part;
- part = ped_disk_next_partition (disk, part)) {
- if (part->type != 0)
- continue;
- _partition_generate_part_entry (part, &ptes[part->num - 1]);
- }
-
- ptes_crc = efi_crc32 (ptes, ptes_size);
-
- /* Write protective MBR */
- if (!_write_pmbr (disk->dev))
- goto error_free_ptes;
-
- /* Write PTH and PTEs */
- _generate_header (disk, 0, ptes_crc, &gpt);
- pth_raw = pth_get_raw (disk->dev, gpt);
- pth_free (gpt);
- if (!ped_device_write (disk->dev, pth_raw, 1, 1))
- goto error_free_ptes;
- if (!ped_device_write (disk->dev, ptes, 2, ptes_size / disk->dev->sector_size))
- goto error_free_ptes;
-
- /* Write Alternate PTH & PTEs */
- _generate_header (disk, 1, ptes_crc, &gpt);
- pth_raw = pth_get_raw (disk->dev, gpt);
- pth_free (gpt);
- if (!ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1))
- goto error_free_ptes;
- if (!ped_device_write (disk->dev, ptes,
- disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
- ptes_size / disk->dev->sector_size))
- goto error_free_ptes;
-
- free (ptes);
- return ped_device_sync (disk->dev);
+ GPTDiskData *gpt_disk_data;
+ GuidPartitionEntry_t *ptes;
+ uint32_t ptes_crc;
+ uint8_t *pth_raw;
+ GuidPartitionTableHeader_t *gpt;
+ PedPartition *part;
+ int ptes_size;
+
+ PED_ASSERT (disk != NULL, goto error);
+ PED_ASSERT (disk->dev != NULL, goto error);
+ PED_ASSERT (disk->disk_specific != NULL, goto error);
+
+ gpt_disk_data = disk->disk_specific;
+
+ ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
+ ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
+ if (!ptes)
+ goto error;
+ memset (ptes, 0, ptes_size);
+ for (part = ped_disk_next_partition (disk, NULL); part;
+ part = ped_disk_next_partition (disk, part))
+ {
+ if (part->type != 0)
+ continue;
+ _partition_generate_part_entry (part, &ptes[part->num - 1]);
+ }
+
+ ptes_crc = efi_crc32 (ptes, ptes_size);
+
+ /* Write protective MBR */
+ if (!_write_pmbr (disk->dev))
+ goto error_free_ptes;
+
+ /* Write PTH and PTEs */
+ /* 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);
+ 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;
+ if (!ped_device_write (disk->dev, ptes, 2,
+ ptes_size / disk->dev->sector_size))
+ goto error_free_ptes;
+
+ /* Write Alternate PTH & PTEs */
+ /* 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)
+ goto error_free_ptes;
+ if (!ped_device_write (disk->dev, ptes,
+ disk->dev->length - 1 -
+ ptes_size / disk->dev->sector_size,
+ ptes_size / disk->dev->sector_size))
+ goto error_free_ptes;
+
+ free (ptes);
+ return ped_device_sync (disk->dev);
error_free_ptes:
- free (ptes);
+ free (ptes);
error:
- return 0;
+ return 0;
}
#endif /* !DISCOVER_ONLY */
static int
-add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
+add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
{
- PedPartition* part;
- PedConstraint* constraint_exact;
- PED_ASSERT(disk != NULL, return 0);
+ PedPartition *part;
+ PedConstraint *constraint_exact;
+ PED_ASSERT (disk != NULL, return 0);
- part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
- start, start + length - 1);
- if (!part)
- goto error;
+ part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
+ start, start + length - 1);
+ if (!part)
+ goto error;
- constraint_exact = ped_constraint_exact (&part->geom);
- if (!ped_disk_add_partition (disk, part, constraint_exact))
- goto error_destroy_constraint;
- ped_constraint_destroy (constraint_exact);
- return 1;
+ constraint_exact = ped_constraint_exact (&part->geom);
+ if (!ped_disk_add_partition (disk, part, constraint_exact))
+ goto error_destroy_constraint;
+ ped_constraint_destroy (constraint_exact);
+ return 1;
error_destroy_constraint:
- ped_constraint_destroy (constraint_exact);
- ped_partition_destroy (part);
+ ped_constraint_destroy (constraint_exact);
+ ped_partition_destroy (part);
error:
- return 0;
+ return 0;
}
-static PedPartition*
-gpt_partition_new (const PedDisk* disk,
- PedPartitionType part_type, const PedFileSystemType* fs_type,
- PedSector start, PedSector end)
+static PedPartition *
+gpt_partition_new (const PedDisk *disk,
+ PedPartitionType part_type,
+ const PedFileSystemType *fs_type, PedSector start,
+ PedSector end)
{
- PedPartition* part;
- GPTPartitionData* gpt_part_data;
-
- part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
- if (!part)
- goto error;
-
- if (part_type != 0)
- return part;
-
- gpt_part_data = part->disk_specific =
- ped_malloc (sizeof (GPTPartitionData));
- if (!gpt_part_data)
- goto error_free_part;
-
- gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
- gpt_part_data->lvm = 0;
- gpt_part_data->raid = 0;
- gpt_part_data->boot = 0;
- gpt_part_data->bios_grub = 0;
- gpt_part_data->hp_service = 0;
- gpt_part_data->hidden = 0;
- gpt_part_data->msftres = 0;
- uuid_generate ((unsigned char*) &gpt_part_data->uuid);
- swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
- strcpy (gpt_part_data->name, "");
- return part;
+ PedPartition *part;
+ GPTPartitionData *gpt_part_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (part_type != 0)
+ return part;
+
+ gpt_part_data = part->disk_specific =
+ ped_malloc (sizeof (GPTPartitionData));
+ if (!gpt_part_data)
+ goto error_free_part;
+
+ gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
+ gpt_part_data->lvm = 0;
+ gpt_part_data->raid = 0;
+ gpt_part_data->boot = 0;
+ gpt_part_data->bios_grub = 0;
+ 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);
+ return part;
error_free_part:
- _ped_partition_free (part);
+ _ped_partition_free (part);
error:
- return NULL;
+ return NULL;
}
-static PedPartition*
-gpt_partition_duplicate (const PedPartition* part)
+static PedPartition *
+gpt_partition_duplicate (const PedPartition *part)
{
- PedPartition* result;
- GPTPartitionData* part_data = part->disk_specific;
- GPTPartitionData* result_data;
+ PedPartition *result;
+ GPTPartitionData *part_data = part->disk_specific;
+ GPTPartitionData *result_data;
- result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
- part->geom.start, part->geom.end);
- if (!result)
- goto error;
- result->num = part->num;
+ result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
+ part->geom.start, part->geom.end);
+ if (!result)
+ goto error;
+ result->num = part->num;
- if (result->type != 0)
- return result;
+ if (result->type != 0)
+ return result;
- result_data = result->disk_specific =
- ped_malloc (sizeof (GPTPartitionData));
- if (!result_data)
- goto error_free_part;
+ result_data = result->disk_specific =
+ ped_malloc (sizeof (GPTPartitionData));
+ if (!result_data)
+ goto error_free_part;
- result_data->type = part_data->type;
- result_data->uuid = part_data->uuid;
- strcpy (result_data->name, part_data->name);
- return result;
+ result_data->type = part_data->type;
+ result_data->uuid = part_data->uuid;
+ strcpy (result_data->name, part_data->name);
+ return result;
error_free_part:
- _ped_partition_free (result);
+ _ped_partition_free (result);
error:
- return NULL;
+ return NULL;
}
static void
gpt_partition_destroy (PedPartition *part)
{
- if (part->type == 0) {
- PED_ASSERT (part->disk_specific != NULL, return);
- free (part->disk_specific);
- }
+ if (part->type == 0)
+ {
+ PED_ASSERT (part->disk_specific != NULL, return);
+ free (part->disk_specific);
+ }
- _ped_partition_free (part);
+ _ped_partition_free (part);
}
static int
-gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+gpt_partition_set_system (PedPartition *part,
+ const PedFileSystemType *fs_type)
{
- GPTPartitionData* gpt_part_data = part->disk_specific;
-
- PED_ASSERT (gpt_part_data != NULL, return 0);
-
- part->fs_type = fs_type;
-
- if (gpt_part_data->lvm) {
- gpt_part_data->type = PARTITION_LVM_GUID;
- return 1;
- }
- if (gpt_part_data->raid) {
- gpt_part_data->type = PARTITION_RAID_GUID;
- return 1;
- }
- if (gpt_part_data->boot) {
- gpt_part_data->type = PARTITION_SYSTEM_GUID;
- return 1;
- }
- if (gpt_part_data->bios_grub) {
- gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
- return 1;
- }
- if (gpt_part_data->hp_service) {
- gpt_part_data->type = PARTITION_HPSERVICE_GUID;
- return 1;
- }
- if (gpt_part_data->msftres) {
- gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
- return 1;
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+
+ PED_ASSERT (gpt_part_data != NULL, return 0);
+
+ part->fs_type = fs_type;
+
+ if (gpt_part_data->lvm)
+ {
+ gpt_part_data->type = PARTITION_LVM_GUID;
+ return 1;
+ }
+ if (gpt_part_data->raid)
+ {
+ gpt_part_data->type = PARTITION_RAID_GUID;
+ return 1;
+ }
+ if (gpt_part_data->boot)
+ {
+ gpt_part_data->type = PARTITION_SYSTEM_GUID;
+ return 1;
+ }
+ if (gpt_part_data->bios_grub)
+ {
+ gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
+ return 1;
+ }
+ if (gpt_part_data->hp_service)
+ {
+ gpt_part_data->type = PARTITION_HPSERVICE_GUID;
+ return 1;
+ }
+ if (gpt_part_data->msftres)
+ {
+ 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)
+ {
+ if (strncmp (fs_type->name, "fat", 3) == 0
+ || strcmp (fs_type->name, "ntfs") == 0)
+ {
+ gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
+ return 1;
}
-
- if (fs_type) {
- if (strncmp (fs_type->name, "fat", 3) == 0
- || strcmp (fs_type->name, "ntfs") == 0) {
- gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
- return 1;
- }
- if (strncmp (fs_type->name, "hfs", 3) == 0) {
- gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
- return 1;
- }
- if (strstr (fs_type->name, "swap")) {
- gpt_part_data->type = PARTITION_SWAP_GUID;
- return 1;
- }
- }
-
- gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
- return 1;
+ if (strncmp (fs_type->name, "hfs", 3) == 0)
+ {
+ gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
+ return 1;
+ }
+ if (strstr (fs_type->name, "swap"))
+ {
+ gpt_part_data->type = PARTITION_SWAP_GUID;
+ return 1;
+ }
+ }
+
+ gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
+ return 1;
}
/* Allocate metadata partitions for the GPTH and PTES */
static int
-gpt_alloc_metadata (PedDisk * disk)
+gpt_alloc_metadata (PedDisk *disk)
{
- PedSector gptlength, pteslength = 0;
- GPTDiskData *gpt_disk_data;
-
- PED_ASSERT(disk != NULL, return 0);
- PED_ASSERT(disk->dev != NULL, return 0);
- PED_ASSERT(disk->disk_specific != NULL, return 0);
- gpt_disk_data = disk->disk_specific;
-
- gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
- disk->dev->sector_size);
- pteslength = ped_div_round_up (gpt_disk_data->entry_count
- * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
-
- /* metadata at the start of the disk includes the MBR */
- if (!add_metadata_part(disk, GPT_PMBR_LBA,
- GPT_PMBR_SECTORS + gptlength + pteslength))
- return 0;
-
- /* metadata at the end of the disk */
- if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
- gptlength + pteslength))
- return 0;
-
- return 1;
+ PedSector gptlength, pteslength = 0;
+ GPTDiskData *gpt_disk_data;
+
+ PED_ASSERT (disk != NULL, return 0);
+ PED_ASSERT (disk->dev != NULL, return 0);
+ PED_ASSERT (disk->disk_specific != NULL, return 0);
+ gpt_disk_data = disk->disk_specific;
+
+ gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
+ disk->dev->sector_size);
+ pteslength = ped_div_round_up (gpt_disk_data->entry_count
+ * sizeof (GuidPartitionEntry_t),
+ disk->dev->sector_size);
+
+ /* metadata at the start of the disk includes the MBR */
+ if (!add_metadata_part (disk, GPT_PMBR_LBA,
+ GPT_PMBR_SECTORS + gptlength + pteslength))
+ return 0;
+
+ /* metadata at the end of the disk */
+ if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
+ gptlength + pteslength))
+ return 0;
+
+ return 1;
}
/* Does nothing, as the read/new/destroy functions maintain part->num */
static int
-gpt_partition_enumerate (PedPartition* part)
+gpt_partition_enumerate (PedPartition *part)
{
- GPTDiskData* gpt_disk_data = part->disk->disk_specific;
- int i;
-
- /* never change the partition numbers */
- if (part->num != -1)
- return 1;
-
- for (i = 1; i <= gpt_disk_data->entry_count; i++) {
- if (!ped_disk_get_partition (part->disk, i)) {
- part->num = i;
- return 1;
- }
- }
+ GPTDiskData *gpt_disk_data = part->disk->disk_specific;
+ int i;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+
+ for (i = 1; i <= gpt_disk_data->entry_count; i++)
+ {
+ if (!ped_disk_get_partition (part->disk, i))
+ {
+ part->num = i;
+ return 1;
+ }
+ }
- PED_ASSERT (0, return 0);
+ PED_ASSERT (0, return 0);
- return 0; /* used if debug is disabled */
+ return 0; /* used if debug is disabled */
}
static int
-gpt_partition_set_flag(PedPartition *part,
- PedPartitionFlag flag,
- int state)
+gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
{
- GPTPartitionData *gpt_part_data;
- PED_ASSERT(part != NULL, return 0);
- PED_ASSERT(part->disk_specific != NULL, return 0);
- gpt_part_data = part->disk_specific;
-
- switch (flag) {
- case PED_PARTITION_BOOT:
- gpt_part_data->boot = state;
- if (state)
- gpt_part_data->raid
- = gpt_part_data->lvm
- = gpt_part_data->bios_grub
- = gpt_part_data->hp_service
- = gpt_part_data->msftres = 0;
- return gpt_partition_set_system (part, part->fs_type);
- case PED_PARTITION_BIOS_GRUB:
- gpt_part_data->bios_grub = state;
- if (state)
- gpt_part_data->raid
- = gpt_part_data->lvm
- = gpt_part_data->boot
- = gpt_part_data->hp_service
- = gpt_part_data->msftres = 0;
- return gpt_partition_set_system (part, part->fs_type);
- case PED_PARTITION_RAID:
- gpt_part_data->raid = state;
- if (state)
- gpt_part_data->boot
- = gpt_part_data->lvm
- = gpt_part_data->bios_grub
- = gpt_part_data->hp_service
- = gpt_part_data->msftres = 0;
- return gpt_partition_set_system (part, part->fs_type);
- case PED_PARTITION_LVM:
- gpt_part_data->lvm = state;
- if (state)
- gpt_part_data->boot
- = gpt_part_data->raid
- = gpt_part_data->bios_grub
- = gpt_part_data->hp_service
- = gpt_part_data->msftres = 0;
- return gpt_partition_set_system (part, part->fs_type);
- case PED_PARTITION_HPSERVICE:
- gpt_part_data->hp_service = state;
- if (state)
- gpt_part_data->boot
- = gpt_part_data->raid
- = gpt_part_data->lvm
- = gpt_part_data->bios_grub
- = gpt_part_data->msftres = 0;
- return gpt_partition_set_system (part, part->fs_type);
- case PED_PARTITION_MSFT_RESERVED:
- gpt_part_data->msftres = 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 = 0;
- return gpt_partition_set_system (part, part->fs_type);
- case PED_PARTITION_HIDDEN:
- gpt_part_data->hidden = state;
- return 1;
- case PED_PARTITION_SWAP:
- case PED_PARTITION_ROOT:
- case PED_PARTITION_LBA:
- default:
- return 0;
- }
- return 1;
+ GPTPartitionData *gpt_part_data;
+ PED_ASSERT (part != NULL, return 0);
+ PED_ASSERT (part->disk_specific != NULL, return 0);
+ gpt_part_data = part->disk_specific;
+
+ switch (flag)
+ {
+ case PED_PARTITION_BOOT:
+ gpt_part_data->boot = state;
+ if (state)
+ 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
+ = 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;
+ if (state)
+ gpt_part_data->raid
+ = gpt_part_data->lvm
+ = gpt_part_data->boot
+ = 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;
+ if (state)
+ gpt_part_data->boot
+ = gpt_part_data->lvm
+ = gpt_part_data->bios_grub
+ = 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;
+ if (state)
+ gpt_part_data->boot
+ = gpt_part_data->raid
+ = gpt_part_data->bios_grub
+ = 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;
+ if (state)
+ gpt_part_data->boot
+ = gpt_part_data->raid
+ = gpt_part_data->lvm
+ = 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;
+ 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->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;
+ return 1;
+ case PED_PARTITION_SWAP:
+ case PED_PARTITION_ROOT:
+ case PED_PARTITION_LBA:
+ default:
+ return 0;
+ }
+ return 1;
}
static int
-gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
+gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
{
- GPTPartitionData *gpt_part_data;
- PED_ASSERT(part->disk_specific != NULL, return 0);
- gpt_part_data = part->disk_specific;
-
- switch (flag) {
- case PED_PARTITION_RAID:
- return gpt_part_data->raid;
- case PED_PARTITION_LVM:
- return gpt_part_data->lvm;
- case PED_PARTITION_BOOT:
- return gpt_part_data->boot;
- case PED_PARTITION_BIOS_GRUB:
- return gpt_part_data->bios_grub;
- case PED_PARTITION_HPSERVICE:
- return gpt_part_data->hp_service;
- case PED_PARTITION_MSFT_RESERVED:
- return gpt_part_data->msftres;
- case PED_PARTITION_HIDDEN:
- return gpt_part_data->hidden;
- case PED_PARTITION_SWAP:
- case PED_PARTITION_LBA:
- case PED_PARTITION_ROOT:
- default:
- return 0;
- }
- return 0;
+ GPTPartitionData *gpt_part_data;
+ PED_ASSERT (part->disk_specific != NULL, return 0);
+ gpt_part_data = part->disk_specific;
+
+ switch (flag)
+ {
+ case PED_PARTITION_RAID:
+ return gpt_part_data->raid;
+ case PED_PARTITION_LVM:
+ return gpt_part_data->lvm;
+ case PED_PARTITION_BOOT:
+ return gpt_part_data->boot;
+ case PED_PARTITION_BIOS_GRUB:
+ return gpt_part_data->bios_grub;
+ case PED_PARTITION_HPSERVICE:
+ 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:
+ case PED_PARTITION_LBA:
+ case PED_PARTITION_ROOT:
+ default:
+ return 0;
+ }
+ return 0;
}
static int
-gpt_partition_is_flag_available(const PedPartition * part,
- PedPartitionFlag flag)
+gpt_partition_is_flag_available (const PedPartition *part,
+ PedPartitionFlag flag)
{
- switch (flag) {
- case PED_PARTITION_RAID:
- case PED_PARTITION_LVM:
- case PED_PARTITION_BOOT:
- case PED_PARTITION_BIOS_GRUB:
- case PED_PARTITION_HPSERVICE:
- case PED_PARTITION_MSFT_RESERVED:
- case PED_PARTITION_HIDDEN:
- return 1;
- case PED_PARTITION_SWAP:
- case PED_PARTITION_ROOT:
- case PED_PARTITION_LBA:
- default:
- return 0;
- }
- return 0;
+ switch (flag)
+ {
+ case PED_PARTITION_RAID:
+ case PED_PARTITION_LVM:
+ case PED_PARTITION_BOOT:
+ 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:
+ case PED_PARTITION_ROOT:
+ case PED_PARTITION_LBA:
+ default:
+ return 0;
+ }
+ return 0;
}
static void
gpt_partition_set_name (PedPartition *part, const char *name)
{
- GPTPartitionData *gpt_part_data = part->disk_specific;
+ GPTPartitionData *gpt_part_data = part->disk_specific;
- strncpy (gpt_part_data->name, name, 36);
- gpt_part_data->name [36] = 0;
+ strncpy (gpt_part_data->name, name, 36);
+ gpt_part_data->name[36] = 0;
}
static const char *
-gpt_partition_get_name (const PedPartition * part)
+gpt_partition_get_name (const PedPartition *part)
{
- GPTPartitionData* gpt_part_data = part->disk_specific;
- return gpt_part_data->name;
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+ return gpt_part_data->name;
}
static int
gpt_get_max_primary_partition_count (const PedDisk *disk)
{
- const GPTDiskData* gpt_disk_data = disk->disk_specific;
- return gpt_disk_data->entry_count;
+ const GPTDiskData *gpt_disk_data = disk->disk_specific;
+ return gpt_disk_data->entry_count;
+}
+
+/*
+ * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
+ * According to the specs the first LBA (LBA0) is not relevant (it exists
+ * to maintain compatibility). on the second LBA(LBA1) gpt places the
+ * header. The header is as big as the block size. After the header we
+ * find the Entry array. Each element of said array, describes each
+ * partition. One can have as much elements as can fit between the end of
+ * the second LBA (where the header ends) and the FirstUsableLBA.
+ * FirstUsableLBA is the first logical block that is used for contents
+ * and is defined in header.
+ *
+ * /---------------------------------------------------\
+ * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
+ * | | BLOCK1 | | |
+ * \---------------------------------------------------/
+ * / \
+ * /----------/ \----------\
+ * /-----------------------------------------\
+ * | E1 | E2 | E3 |...............| EN |
+ * \-----------------------------------------/
+ *
+ * The number of possible partitions or supported partitions is:
+ * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
+ * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
+ */
+static bool
+gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
+{
+ GuidPartitionTableHeader_t *pth = NULL;
+ uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
+
+ if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
+ || ped_device_read (disk->dev, pth_raw,
+ disk->dev->length, GPT_HEADER_SECTORS))
+ pth = pth_new_from_raw (disk->dev, pth_raw);
+ free (pth_raw);
+
+ if (pth == NULL)
+ return false;
+
+ *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
+ / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
+ pth_free (pth);
+ return true;
}
-static PedConstraint*
-_non_metadata_constraint (const PedDisk* disk)
+static PedConstraint *
+_non_metadata_constraint (const PedDisk *disk)
{
- GPTDiskData* gpt_disk_data = disk->disk_specific;
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
- return ped_constraint_new_from_max (&gpt_disk_data->data_area);
+ return ped_constraint_new_from_max (&gpt_disk_data->data_area);
}
static int
-gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
+gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
{
- PED_ASSERT (part != NULL, return 0);
+ PED_ASSERT (part != NULL, return 0);
- if (_ped_partition_attempt_align (part, constraint,
- _non_metadata_constraint (part->disk)))
- return 1;
+ if (_ped_partition_attempt_align (part, constraint,
+ _non_metadata_constraint (part->disk)))
+ return 1;
#ifndef DISCOVER_ONLY
- ped_exception_throw (
- PED_EXCEPTION_ERROR,
- PED_EXCEPTION_CANCEL,
- _("Unable to satisfy all constraints on the partition."));
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
#endif
- return 0;
+ return 0;
}
-static PedDiskOps gpt_disk_ops = {
- probe: gpt_probe,
-#ifndef DISCOVER_ONLY
- clobber: gpt_clobber,
-#else
- clobber: NULL,
-#endif
- alloc: gpt_alloc,
- duplicate: gpt_duplicate,
- free: gpt_free,
- read: gpt_read,
-#ifndef DISCOVER_ONLY
- write: gpt_write,
-#else
- write: NULL,
-#endif
- 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,
- alloc_metadata: gpt_alloc_metadata,
- get_max_primary_partition_count: gpt_get_max_primary_partition_count
+#include "pt-common.h"
+PT_define_limit_functions (gpt)
+
+static PedDiskOps gpt_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,
+
+ PT_op_function_initializers (gpt)
};
-static PedDiskType gpt_disk_type = {
- next: NULL,
- name: "gpt",
- ops: &gpt_disk_ops,
- features: PED_DISK_TYPE_PARTITION_NAME
+static PedDiskType gpt_disk_type =
+{
+ next: NULL,
+ name: "gpt",
+ ops: &gpt_disk_ops,
+ features: PED_DISK_TYPE_PARTITION_NAME
};
void
-ped_disk_gpt_init()
+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);
+ ped_disk_type_register (&gpt_disk_type);
}
void
-ped_disk_gpt_done()
+ped_disk_gpt_done ()
{
- ped_disk_type_unregister (&gpt_disk_type);
+ ped_disk_type_unregister (&gpt_disk_type);
}
+
+verify (sizeof (GuidPartitionEntryAttributes_t) == 8);
+verify (sizeof (GuidPartitionEntry_t) == 128);