2 libparted - a library for manipulating disk partitions
4 original version by Matt Domsch <Matt_Domsch@dell.com>
5 Disclaimed into the Public Domain
7 Portions Copyright (C) 2001, 2002, 2003, 2005, 2006
8 Free Software Foundation, Inc.
10 EFI GUID Partition Table handling
11 Per Intel EFI Specification v1.02
12 http://developer.intel.com/technology/efi/efi.htm
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include <parted/parted.h>
32 #include <parted/debug.h>
33 #include <parted/endian.h>
34 #include <parted/crc32.h>
39 #include <sys/types.h>
40 #include <sys/ioctl.h>
43 #include <uuid/uuid.h>
47 # define _(String) gettext (String)
49 # define _(String) (String)
50 #endif /* ENABLE_NLS */
52 #define EFI_PMBR_OSTYPE_EFI 0xEE
53 #define MSDOS_MBR_SIGNATURE 0xaa55
55 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
57 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
58 * so some implementors got confused...
60 #define GPT_HEADER_REVISION_V1_02 0x00010200
61 #define GPT_HEADER_REVISION_V1_00 0x00010000
62 #define GPT_HEADER_REVISION_V0_99 0x00009900
64 typedef uint16_t efi_char16_t; /* UNICODE character */
69 uint16_t time_hi_and_version;
70 uint8_t clock_seq_hi_and_reserved;
71 uint8_t clock_seq_low;
73 } /* __attribute__ ((packed)) */ efi_guid_t;
74 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
75 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
76 * data. It turns out we don't need it in this case, so it doesn't break
80 #define UNUSED_ENTRY_GUID \
81 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
82 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
83 #define PARTITION_SYSTEM_GUID \
84 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
85 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
86 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
87 #define LEGACY_MBR_PARTITION_GUID \
88 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
89 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
90 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
91 #define PARTITION_MSFT_RESERVED_GUID \
92 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
93 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
94 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
95 #define PARTITION_BASIC_DATA_GUID \
96 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
97 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
98 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
99 #define PARTITION_RAID_GUID \
100 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
101 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
102 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
103 #define PARTITION_SWAP_GUID \
104 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
105 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
106 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
107 #define PARTITION_LVM_GUID \
108 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
109 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
110 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
111 #define PARTITION_RESERVED_GUID \
112 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
113 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
114 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
115 #define PARTITION_HPSERVICE_GUID \
116 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
117 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
118 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
119 #define PARTITION_APPLE_HFS_GUID \
120 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
121 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
122 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
124 typedef struct _GuidPartitionTableHeader_t {
128 uint32_t HeaderCRC32;
131 uint64_t AlternateLBA;
132 uint64_t FirstUsableLBA;
133 uint64_t LastUsableLBA;
135 uint64_t PartitionEntryLBA;
136 uint32_t NumberOfPartitionEntries;
137 uint32_t SizeOfPartitionEntry;
138 uint32_t PartitionEntryArrayCRC32;
140 } __attribute__ ((packed)) GuidPartitionTableHeader_t;
142 typedef struct _GuidPartitionEntryAttributes_t {
143 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
144 uint64_t RequiredToFunction:1;
145 uint64_t Reserved:47;
146 uint64_t GuidSpecific:16;
148 # warning "Using crippled partition entry type"
149 uint32_t RequiredToFunction:1;
150 uint32_t Reserved:32;
152 uint32_t GuidSpecific:16;
154 } __attribute__ ((packed)) GuidPartitionEntryAttributes_t;
156 typedef struct _GuidPartitionEntry_t {
157 efi_guid_t PartitionTypeGuid;
158 efi_guid_t UniquePartitionGuid;
159 uint64_t StartingLBA;
161 GuidPartitionEntryAttributes_t Attributes;
162 efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
163 } __attribute__ ((packed)) GuidPartitionEntry_t;
165 #define GPT_PMBR_LBA 0
166 #define GPT_PMBR_SECTORS 1
167 #define GPT_PRIMARY_HEADER_LBA 1
168 #define GPT_HEADER_SECTORS 1
169 #define GPT_PRIMARY_PART_TABLE_LBA 2
172 These values are only defaults. The actual on-disk structures
173 may define different sizes, so use those unless creating a new GPT disk!
176 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
178 /* Number of actual partition entries should be calculated as: */
179 #define GPT_DEFAULT_PARTITION_ENTRIES \
180 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
181 sizeof(GuidPartitionEntry_t))
184 typedef struct _PartitionRecord_t {
185 /* Not used by EFI firmware. Set to 0x80 to indicate that this
186 is the bootable legacy partition. */
187 uint8_t BootIndicator;
189 /* Start of partition in CHS address, not used by EFI firmware. */
192 /* Start of partition in CHS address, not used by EFI firmware. */
195 /* Start of partition in CHS address, not used by EFI firmware. */
198 /* OS type. A value of 0xEF defines an EFI system partition.
199 Other values are reserved for legacy operating systems, and
200 allocated independently of the EFI specification. */
203 /* End of partition in CHS address, not used by EFI firmware. */
206 /* End of partition in CHS address, not used by EFI firmware. */
209 /* End of partition in CHS address, not used by EFI firmware. */
212 /* Starting LBA address of the partition on the disk. Used by
213 EFI firmware to define the start of the partition. */
214 uint32_t StartingLBA;
216 /* Size of partition in LBA. Used by EFI firmware to determine
217 the size of the partition. */
219 } __attribute__ ((packed)) PartitionRecord_t;
221 /* Protected Master Boot Record & Legacy MBR share same structure */
222 /* Needs to be packed because the u16s force misalignment. */
223 typedef struct _LegacyMBR_t {
224 uint8_t BootCode[440];
225 uint32_t UniqueMBRSignature;
227 PartitionRecord_t PartitionRecord[4];
229 } __attribute__ ((packed)) LegacyMBR_t;
231 /* uses libparted's disk_specific field in PedDisk, to store our info */
232 typedef struct _GPTDiskData {
233 PedGeometry data_area;
238 /* uses libparted's disk_specific field in PedPartition, to store our info */
239 typedef struct _GPTPartitionData {
251 static PedDiskType gpt_disk_type;
254 static inline uint32_t
255 pth_get_size (const PedDevice* dev)
257 return GPT_HEADER_SECTORS * dev->sector_size;
261 static inline uint32_t
262 pth_get_size_static (const PedDevice* dev)
264 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
268 static inline uint32_t
269 pth_get_size_rsv2 (const PedDevice* dev)
271 return pth_get_size(dev) - pth_get_size_static(dev);
275 static GuidPartitionTableHeader_t*
276 pth_new (const PedDevice* dev)
278 GuidPartitionTableHeader_t* pth = ped_malloc (
279 sizeof (GuidPartitionTableHeader_t)
282 pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
288 static GuidPartitionTableHeader_t*
289 pth_new_zeroed (const PedDevice* dev)
291 GuidPartitionTableHeader_t* pth = pth_new (dev);
293 memset (pth, 0, pth_get_size_static (dev));
294 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
300 static GuidPartitionTableHeader_t*
301 pth_new_from_raw (const PedDevice* dev, const uint8_t* pth_raw)
303 GuidPartitionTableHeader_t* pth = pth_new (dev);
305 PED_ASSERT (pth_raw != NULL, return 0);
307 memcpy (pth, pth_raw, pth_get_size_static (dev));
308 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
309 pth_get_size_rsv2 (dev));
315 pth_free (GuidPartitionTableHeader_t* pth)
317 PED_ASSERT (pth != NULL, return);
318 PED_ASSERT (pth->Reserved2 != NULL, return);
320 ped_free (pth->Reserved2);
325 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
327 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
328 int size_static = pth_get_size_static (dev);
330 PED_ASSERT (pth != NULL, return 0);
331 PED_ASSERT (pth->Reserved2 != NULL, return 0);
333 memcpy (pth_raw, pth, size_static);
334 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
341 * swap_uuid_and_efi_guid() - converts between uuid formats
342 * @uuid - uuid_t in either format (converts it to the other)
344 * There are two different representations for Globally Unique Identifiers
347 * The RFC specifies a UUID as a string of 16 bytes, essentially
348 * a big-endian array of char.
349 * Intel, in their EFI Specification, references the same RFC, but
350 * then defines a GUID as a structure of little-endian fields.
351 * Coincidentally, both structures have the same format when unparsed.
353 * When read from disk, EFI GUIDs are in struct of little endian format,
354 * and need to be converted to be treated as uuid_t in memory.
356 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
361 swap_uuid_and_efi_guid(uuid_t uuid)
364 efi_guid_t *guid = (efi_guid_t *)uuid;
366 PED_ASSERT(uuid != NULL, return);
367 guid->time_low = PED_SWAP32(guid->time_low);
368 guid->time_mid = PED_SWAP16(guid->time_mid);
369 guid->time_hi_and_version = PED_SWAP16(guid->time_hi_and_version);
372 /* returns the EFI-style CRC32 value for buf
373 * This function uses the crc32 function by Gary S. Brown,
374 * but seeds the function with ~0, and xor's with ~0 at the end.
376 static inline uint32_t
377 efi_crc32(const void *buf, unsigned long len)
379 return (__efi_crc32(buf, len, ~0L) ^ ~0L);
382 static inline uint32_t
383 pth_crc32(const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
385 uint8_t* pth_raw = pth_get_raw (dev, pth);
388 PED_ASSERT (dev != NULL, return 0);
389 PED_ASSERT (pth != NULL, return 0);
391 crc32 = efi_crc32 (pth_raw, pth_get_size_static (dev));
399 guid_cmp (efi_guid_t left, efi_guid_t right)
401 return memcmp(&left, &right, sizeof(efi_guid_t));
404 /* checks if 'mbr' is a protective MBR partition table */
406 _pmbr_is_valid (const LegacyMBR_t* mbr)
410 PED_ASSERT(mbr != NULL, return 0);
412 if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
414 for (i = 0; i < 4; i++) {
415 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
422 gpt_probe (const PedDevice * dev)
424 GuidPartitionTableHeader_t* gpt = NULL;
425 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
426 LegacyMBR_t legacy_mbr;
427 int gpt_sig_found = 0;
429 PED_ASSERT (dev != NULL, return 0);
431 if (ped_device_read(dev, pth_raw, 1, GPT_HEADER_SECTORS)
432 || ped_device_read(dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS)) {
433 gpt = pth_new_from_raw (dev, pth_raw);
434 if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
447 if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) {
448 if (!_pmbr_is_valid (&legacy_mbr)) {
449 int ex_status = ped_exception_throw (
450 PED_EXCEPTION_WARNING,
451 PED_EXCEPTION_YES_NO,
452 _("%s contains GPT signatures, indicating that it has "
453 "a GPT table. However, it does not have a valid "
454 "fake msdos partition table, as it should. Perhaps "
455 "it was corrupted -- possibly by a program that "
456 "doesn't understand GPT partition tables. Or "
457 "perhaps you deleted the GPT table, and are now "
458 "using an msdos partition table. Is this a GPT "
461 if (ex_status == PED_EXCEPTION_NO)
469 #ifndef DISCOVER_ONLY
470 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
472 gpt_clobber(PedDevice * dev)
475 uint8_t* zeroed_pth_raw = ped_malloc (pth_get_size (dev));
476 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
477 GuidPartitionTableHeader_t* gpt;
478 GuidPartitionEntry_t ptes[GPT_DEFAULT_PARTITION_ENTRIES];
480 PED_ASSERT (dev != NULL, return 0);
482 memset(&pmbr, 0, sizeof(pmbr));
483 memset(zeroed_pth_raw, 0, pth_get_size (dev));
486 * TO DISCUSS: check whether checksum is correct?
487 * If not, we might get a wrong AlternateLBA field and destroy
488 * one sector of random data.
490 if (!ped_device_read(dev, pth_raw,
491 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
494 gpt = pth_new_from_raw (dev, pth_raw);
496 if (!ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
497 goto error_free_with_gpt;
498 if (!ped_device_write(dev, &zeroed_pth_raw,
499 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
500 goto error_free_with_gpt;
501 if (!ped_device_write(dev, &zeroed_pth_raw, dev->length - GPT_HEADER_SECTORS,
503 goto error_free_with_gpt;
505 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1) {
506 if (!ped_device_write(dev, gpt,
507 PED_LE64_TO_CPU (gpt->AlternateLBA),
520 ped_free (zeroed_pth_raw);
523 #endif /* !DISCOVER_ONLY */
526 gpt_alloc (const PedDevice * dev)
529 GPTDiskData *gpt_disk_data;
530 PedSector data_start, data_end;
532 disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_disk_type);
535 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
536 if (!disk->disk_specific)
537 goto error_free_disk;
539 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
540 data_end = dev->length - 2
541 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
542 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
543 data_end - data_start + 1);
544 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
545 uuid_generate ((unsigned char*) &gpt_disk_data->uuid);
546 swap_uuid_and_efi_guid((unsigned char*)(&gpt_disk_data->uuid));
556 gpt_duplicate (const PedDisk* disk)
559 GPTDiskData* new_disk_data;
560 GPTDiskData* old_disk_data;
562 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
566 old_disk_data = disk->disk_specific;
567 new_disk_data = new_disk->disk_specific;
569 ped_geometry_init (&new_disk_data->data_area, disk->dev,
570 old_disk_data->data_area.start,
571 old_disk_data->data_area.length);
572 new_disk_data->entry_count = old_disk_data->entry_count;
573 new_disk_data->uuid = old_disk_data->uuid;
578 gpt_free(PedDisk * disk)
580 ped_disk_delete_all (disk);
581 ped_free (disk->disk_specific);
582 _ped_disk_free (disk);
586 _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
588 uint32_t crc, origcrc;
590 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
592 if (PED_LE32_TO_CPU (gpt->HeaderSize)
593 > pth_get_size_static (dev))
596 origcrc = gpt->HeaderCRC32;
597 gpt->HeaderCRC32 = 0;
598 crc = pth_crc32 (dev, gpt);
599 gpt->HeaderCRC32 = origcrc;
601 return crc == PED_LE32_TO_CPU (origcrc);
605 _read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt,
608 uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
610 PED_ASSERT (dev != NULL, return 0);
612 if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) {
617 *gpt = pth_new_from_raw (dev, pth_raw);
621 if (_header_is_valid (dev, *gpt))
629 _parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt,
632 GPTDiskData* gpt_disk_data = disk->disk_specific;
633 PedSector first_usable;
634 PedSector last_usable;
635 PedSector last_usable_if_grown, last_usable_min_default;
636 static int asked_already;
638 PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
640 #ifndef DISCOVER_ONLY
641 if (PED_CPU_TO_LE32 (gpt->Revision) > GPT_HEADER_REVISION_V1_02
642 || PED_CPU_TO_LE32 (gpt->HeaderSize) != pth_get_size_static (
644 if (ped_exception_throw (
645 PED_EXCEPTION_WARNING,
646 PED_EXCEPTION_IGNORE_CANCEL,
647 _("The format of the GPT partition table is version "
648 "%x, which is newer than what Parted can "
649 "recognise. Please tell us! bug-parted@gnu.org"),
650 PED_CPU_TO_LE32 (gpt->Revision))
651 != PED_EXCEPTION_IGNORE)
656 first_usable = PED_CPU_TO_LE64 (gpt->FirstUsableLBA);
657 last_usable = PED_CPU_TO_LE64 (gpt->LastUsableLBA);
661 Need to check whether the volume has grown, the LastUsableLBA is
662 normally set to disk->dev->length - 2 - ptes_size (at least for parted
663 created volumes), where ptes_size is the number of entries *
664 size of each entry / sector size or 16k / sector size, whatever the greater.
665 If the volume has grown, offer the user the chance to use the new
666 space or continue with the current usable area. Only ask once per
671 = PED_CPU_TO_LE64 (disk->dev->length - 2 -
672 ((PedSector)(PED_CPU_TO_LE32(gpt->NumberOfPartitionEntries)) *
673 (PedSector)(PED_CPU_TO_LE32(gpt->SizeOfPartitionEntry)) /
674 disk->dev->sector_size));
676 last_usable_min_default = disk->dev->length - 2 -
677 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
679 if ( last_usable_if_grown > last_usable_min_default ) {
681 last_usable_if_grown = last_usable_min_default;
685 PED_ASSERT (last_usable > first_usable, return 0);
686 PED_ASSERT (last_usable <= disk->dev->length, return 0);
688 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
689 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
691 if ( !asked_already && last_usable < last_usable_if_grown ) {
693 PedExceptionOption q;
695 q = ped_exception_throw (PED_EXCEPTION_WARNING,
696 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
697 _("Not all of the space available to %s appears "
698 "to be used, you can fix the GPT to use all of the "
699 "space (an extra %llu blocks) or continue with the "
700 "current setting? "), disk->dev->path,
701 (uint64_t)(last_usable_if_grown - last_usable));
704 if (q == PED_EXCEPTION_FIX) {
706 last_usable = last_usable_if_grown;
710 else if (q != PED_EXCEPTION_UNHANDLED ) {
716 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
717 first_usable, last_usable - first_usable + 1);
720 gpt_disk_data->entry_count
721 = PED_CPU_TO_LE32 (gpt->NumberOfPartitionEntries);
722 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
723 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
725 gpt_disk_data->uuid = gpt->DiskGUID;
731 _parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte)
734 GPTPartitionData* gpt_part_data;
737 part = ped_partition_new (disk, 0, NULL,
738 PED_LE64_TO_CPU(pte->StartingLBA),
739 PED_LE64_TO_CPU(pte->EndingLBA));
743 gpt_part_data = part->disk_specific;
744 gpt_part_data->type = pte->PartitionTypeGuid;
745 gpt_part_data->uuid = pte->UniquePartitionGuid;
746 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
747 gpt_part_data->name[i] = (efi_char16_t) PED_LE16_TO_CPU(
748 (uint16_t) pte->PartitionName[i]);
749 gpt_part_data->name[i] = 0;
751 gpt_part_data->lvm = gpt_part_data->raid
752 = gpt_part_data->boot = gpt_part_data->hp_service
753 = gpt_part_data->hidden = gpt_part_data->msftres = 0;
755 if (pte->Attributes.RequiredToFunction & 0x1)
756 gpt_part_data->hidden = 1;
758 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
759 gpt_part_data->boot = 1;
760 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
761 gpt_part_data->raid = 1;
762 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
763 gpt_part_data->lvm = 1;
764 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
765 gpt_part_data->hp_service = 1;
766 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
767 gpt_part_data->msftres = 1;
772 /************************************************************
773 * Intel is changing the EFI Spec. (after v1.02) to say that a
774 * disk is considered to have a GPT label only if the GPT
775 * structures are correct, and the MBR is actually a Protective
776 * MBR (has one 0xEE type partition).
777 * Problem occurs when a GPT-partitioned disk is then
778 * edited with a legacy (non-GPT-aware) application, such as
779 * fdisk (which doesn't generally erase the PGPT or AGPT).
780 * How should such a disk get handled? As a GPT disk (throwing
781 * away the fdisk changes), or as an MSDOS disk (throwing away
782 * the GPT information). Previously, I've taken the GPT-is-right,
783 * MBR is wrong, approach, to stay consistent with the EFI Spec.
784 * Intel disagrees, saying the disk should then be treated
785 * as having a msdos label, not a GPT label. If this is true,
786 * then what's the point of having an AGPT, since if the PGPT
787 * is screwed up, likely the PMBR is too, and the PMBR becomes
788 * a single point of failure.
789 * So, in the Linux kernel, I'm going to test for PMBR, and
790 * warn if it's not there, and treat the disk as MSDOS, with a note
791 * for users to use Parted to "fix up" their disk if they
792 * really want it to be considered GPT.
793 ************************************************************/
795 gpt_read (PedDisk * disk)
797 GPTDiskData *gpt_disk_data = disk->disk_specific;
798 GuidPartitionTableHeader_t* gpt;
799 GuidPartitionEntry_t* ptes;
802 #ifndef DISCOVER_ONLY
806 ped_disk_delete_all (disk);
809 * motivation: let the user decide about the pmbr... during
810 * ped_disk_probe(), they probably didn't get a choice...
812 if (!gpt_probe (disk->dev))
815 if (_read_header (disk->dev, &gpt, 1)) {
816 PED_ASSERT ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
817 <= disk->dev->length - 1, goto error_free_gpt);
818 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
819 < disk->dev->length - 1) {
820 char* zeros = ped_malloc (pth_get_size (disk->dev));
822 #ifndef DISCOVER_ONLY
823 if (ped_exception_throw (
825 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
826 _("The backup GPT table is not at the end of the disk, as it "
827 "should be. This might mean that another operating system "
828 "believes the disk is smaller. Fix, by moving the backup "
829 "to the end (and removing the old backup)?"))
830 == PED_EXCEPTION_CANCEL)
834 memset (zeros, 0, disk->dev->sector_size);
835 ped_device_write (disk->dev, zeros,
836 PED_LE64_TO_CPU (gpt->AlternateLBA),
838 #endif /* !DISCOVER_ONLY */
840 } else { /* primary GPT *not* ok */
841 int alternate_ok = 0;
843 #ifndef DISCOVER_ONLY
847 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
848 < disk->dev->length - 1) {
849 alternate_ok = _read_header (disk->dev, &gpt,
850 PED_LE64_TO_CPU(gpt->AlternateLBA));
853 alternate_ok = _read_header (disk->dev, &gpt,
854 disk->dev->length - 1);
858 if (ped_exception_throw (
860 PED_EXCEPTION_OK_CANCEL,
861 _("The primary GPT table is corrupt, but the "
862 "backup appears OK, so that will be used."))
863 == PED_EXCEPTION_CANCEL)
866 ped_exception_throw (
868 PED_EXCEPTION_CANCEL,
869 _("Both the primary and backup GPT tables "
870 "are corrupt. Try making a fresh table, "
871 "and using Parted's rescue feature to "
872 "recover partitions."));
877 if (!_parse_header (disk, gpt, &write_back))
881 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
882 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
883 if (!ped_device_read (disk->dev, ptes,
884 PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
885 ptes_size / disk->dev->sector_size))
886 goto error_free_ptes;
888 for (i = 0; i < gpt_disk_data->entry_count; i++) {
890 PedConstraint* constraint_exact;
892 if (!guid_cmp (ptes[i].PartitionTypeGuid, UNUSED_ENTRY_GUID))
895 part = _parse_part_entry (disk, &ptes[i]);
897 goto error_delete_all;
899 part->fs_type = ped_file_system_probe (&part->geom);
902 constraint_exact = ped_constraint_exact (&part->geom);
903 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
904 ped_partition_destroy (part);
905 goto error_delete_all;
907 ped_constraint_destroy (constraint_exact);
911 #ifndef DISCOVER_ONLY
913 ped_disk_commit_to_dev (disk);
919 ped_disk_delete_all (disk);
928 #ifndef DISCOVER_ONLY
929 /* Writes the protective MBR (to keep DOS happy) */
931 _write_pmbr (PedDevice * dev)
935 memset(&pmbr, 0, sizeof(pmbr));
936 pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
937 pmbr.PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
938 pmbr.PartitionRecord[0].StartSector = 1;
939 pmbr.PartitionRecord[0].EndHead = 0xFE;
940 pmbr.PartitionRecord[0].EndSector = 0xFF;
941 pmbr.PartitionRecord[0].EndTrack = 0xFF;
942 pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
943 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
944 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
946 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
948 return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS);
952 _generate_header (PedDisk* disk, int alternate, uint32_t ptes_crc,
953 GuidPartitionTableHeader_t** gpt_p)
955 GPTDiskData* gpt_disk_data = disk->disk_specific;
956 GuidPartitionTableHeader_t* gpt;
958 *gpt_p = pth_new_zeroed (disk->dev);
962 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
963 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
966 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
967 gpt->HeaderCRC32 = 0;
971 PedSector ptes_size = gpt_disk_data->entry_count
972 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
974 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
975 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
976 gpt->PartitionEntryLBA
977 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
979 gpt->MyLBA = PED_CPU_TO_LE64 (1);
980 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
981 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
984 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
985 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
986 gpt->DiskGUID = gpt_disk_data->uuid;
987 gpt->NumberOfPartitionEntries
988 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
989 gpt->SizeOfPartitionEntry
990 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
991 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
992 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
996 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
998 GPTPartitionData* gpt_part_data = part->disk_specific;
1001 PED_ASSERT (gpt_part_data != NULL, return);
1003 pte->PartitionTypeGuid = gpt_part_data->type;
1004 pte->UniquePartitionGuid = gpt_part_data->uuid;
1005 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1006 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1007 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1009 if (gpt_part_data->hidden)
1010 pte->Attributes.RequiredToFunction = 1;
1012 for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1013 pte->PartitionName[i]
1014 = (efi_char16_t) PED_CPU_TO_LE16(
1015 (uint16_t) gpt_part_data->name[i]);
1019 gpt_write(PedDisk * disk)
1021 GPTDiskData* gpt_disk_data;
1022 GuidPartitionEntry_t* ptes;
1024 uint8_t* pth_raw = ped_malloc (pth_get_size (disk->dev));
1025 GuidPartitionTableHeader_t* gpt;
1030 PED_ASSERT (disk != NULL, goto error);
1031 PED_ASSERT (disk->dev != NULL, goto error);
1032 PED_ASSERT (disk->disk_specific != NULL, goto error);
1034 gpt_disk_data = disk->disk_specific;
1036 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1037 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1040 memset (ptes, 0, ptes_size);
1041 for (part = ped_disk_next_partition (disk, NULL); part;
1042 part = ped_disk_next_partition (disk, part)) {
1043 if (part->type != 0)
1045 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1048 ptes_crc = efi_crc32 (ptes, ptes_size);
1050 /* Write protective MBR */
1051 if (!_write_pmbr (disk->dev))
1052 goto error_free_ptes;
1054 /* Write PTH and PTEs */
1055 _generate_header (disk, 0, ptes_crc, &gpt);
1056 pth_raw = pth_get_raw (disk->dev, gpt);
1057 if (!ped_device_write (disk->dev, pth_raw, 1, 1))
1058 goto error_free_ptes;
1059 if (!ped_device_write (disk->dev, ptes, 2, ptes_size / disk->dev->sector_size))
1060 goto error_free_ptes;
1062 /* Write Alternate PTH & PTEs */
1063 _generate_header (disk, 1, ptes_crc, &gpt);
1064 pth_raw = pth_get_raw (disk->dev, gpt);
1065 if (!ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1))
1066 goto error_free_ptes;
1067 if (!ped_device_write (disk->dev, ptes,
1068 disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1069 ptes_size / disk->dev->sector_size))
1070 goto error_free_ptes;
1073 return ped_device_sync (disk->dev);
1080 #endif /* !DISCOVER_ONLY */
1083 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1086 PedConstraint* constraint_exact;
1087 PED_ASSERT(disk != NULL, return 0);
1089 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1090 start, start + length - 1);
1094 constraint_exact = ped_constraint_exact (&part->geom);
1095 if (!ped_disk_add_partition (disk, part, constraint_exact))
1096 goto error_destroy_constraint;
1097 ped_constraint_destroy (constraint_exact);
1100 error_destroy_constraint:
1101 ped_constraint_destroy (constraint_exact);
1103 ped_partition_destroy (part);
1108 static PedPartition*
1109 gpt_partition_new (const PedDisk* disk,
1110 PedPartitionType part_type, const PedFileSystemType* fs_type,
1111 PedSector start, PedSector end)
1114 GPTPartitionData* gpt_part_data;
1116 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1123 gpt_part_data = part->disk_specific =
1124 ped_malloc (sizeof (GPTPartitionData));
1126 goto error_free_part;
1128 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1129 gpt_part_data->lvm = 0;
1130 gpt_part_data->raid = 0;
1131 gpt_part_data->boot = 0;
1132 gpt_part_data->hp_service = 0;
1133 gpt_part_data->hidden = 0;
1134 gpt_part_data->msftres = 0;
1135 uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1136 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1137 strcpy (gpt_part_data->name, "");
1141 _ped_partition_free (part);
1146 static PedPartition*
1147 gpt_partition_duplicate (const PedPartition* part)
1149 PedPartition* result;
1150 GPTPartitionData* part_data = part->disk_specific;
1151 GPTPartitionData* result_data;
1153 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1154 part->geom.start, part->geom.end);
1157 result->num = part->num;
1159 if (result->type != 0)
1162 result_data = result->disk_specific =
1163 ped_malloc (sizeof (GPTPartitionData));
1165 goto error_free_part;
1167 result_data->type = part_data->type;
1168 result_data->uuid = part_data->uuid;
1169 strcpy (result_data->name, part_data->name);
1173 _ped_partition_free (result);
1179 gpt_partition_destroy (PedPartition *part)
1181 if (part->type == 0) {
1182 PED_ASSERT (part->disk_specific != NULL, return);
1183 ped_free (part->disk_specific);
1186 _ped_partition_free (part);
1190 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1192 GPTPartitionData* gpt_part_data = part->disk_specific;
1194 PED_ASSERT (gpt_part_data != NULL, return 0);
1196 part->fs_type = fs_type;
1198 if (gpt_part_data->lvm) {
1199 gpt_part_data->type = PARTITION_LVM_GUID;
1202 if (gpt_part_data->raid) {
1203 gpt_part_data->type = PARTITION_RAID_GUID;
1206 if (gpt_part_data->boot) {
1207 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1210 if (gpt_part_data->hp_service) {
1211 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1214 if (gpt_part_data->msftres) {
1215 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1220 if (strncmp (fs_type->name, "fat", 3) == 0
1221 || strcmp (fs_type->name, "ntfs") == 0) {
1222 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1225 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1226 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1229 if (strstr (fs_type->name, "swap")) {
1230 gpt_part_data->type = PARTITION_SWAP_GUID;
1235 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1239 /* Allocate metadata partitions for the GPTH and PTES */
1241 gpt_alloc_metadata (PedDisk * disk)
1243 PedSector gptlength, pteslength = 0;
1244 GPTDiskData *gpt_disk_data;
1246 PED_ASSERT(disk != NULL, return 0);
1247 PED_ASSERT(disk->dev != NULL, return 0);
1248 PED_ASSERT(disk->disk_specific != NULL, return 0);
1249 gpt_disk_data = disk->disk_specific;
1251 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1252 disk->dev->sector_size);
1253 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1254 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1256 /* metadata at the start of the disk includes the MBR */
1257 if (!add_metadata_part(disk, GPT_PMBR_LBA,
1258 GPT_PMBR_SECTORS + gptlength + pteslength))
1261 /* metadata at the end of the disk */
1262 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1263 gptlength + pteslength))
1269 /* Does nothing, as the read/new/destroy functions maintain part->num */
1271 gpt_partition_enumerate (PedPartition* part)
1273 GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1276 /* never change the partition numbers */
1277 if (part->num != -1)
1280 for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1281 if (!ped_disk_get_partition (part->disk, i)) {
1287 PED_ASSERT (0, return 0);
1291 gpt_partition_set_flag(PedPartition *part,
1292 PedPartitionFlag flag,
1295 GPTPartitionData *gpt_part_data;
1296 PED_ASSERT(part != NULL, return 0);
1297 PED_ASSERT(part->disk_specific != NULL, return 0);
1298 gpt_part_data = part->disk_specific;
1301 case PED_PARTITION_BOOT:
1302 gpt_part_data->boot = state;
1305 = gpt_part_data->lvm
1306 = gpt_part_data->hp_service
1307 = gpt_part_data->msftres = 0;
1308 return gpt_partition_set_system (part, part->fs_type);
1309 case PED_PARTITION_RAID:
1310 gpt_part_data->raid = state;
1313 = gpt_part_data->lvm
1314 = gpt_part_data->hp_service
1315 = gpt_part_data->msftres = 0;
1316 return gpt_partition_set_system (part, part->fs_type);
1317 case PED_PARTITION_LVM:
1318 gpt_part_data->lvm = state;
1321 = gpt_part_data->raid
1322 = gpt_part_data->hp_service
1323 = gpt_part_data->msftres = 0;
1324 return gpt_partition_set_system (part, part->fs_type);
1325 case PED_PARTITION_HPSERVICE:
1326 gpt_part_data->hp_service = state;
1329 = gpt_part_data->raid
1330 = gpt_part_data->lvm
1331 = gpt_part_data->msftres = 0;
1332 return gpt_partition_set_system (part, part->fs_type);
1333 case PED_PARTITION_MSFT_RESERVED:
1334 gpt_part_data->msftres = state;
1337 = gpt_part_data->raid
1338 = gpt_part_data->lvm
1339 = gpt_part_data->hp_service = 0;
1340 return gpt_partition_set_system (part, part->fs_type);
1341 case PED_PARTITION_HIDDEN:
1342 gpt_part_data->hidden = state;
1344 case PED_PARTITION_SWAP:
1345 case PED_PARTITION_ROOT:
1346 case PED_PARTITION_LBA:
1354 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1356 GPTPartitionData *gpt_part_data;
1357 PED_ASSERT(part->disk_specific != NULL, return 0);
1358 gpt_part_data = part->disk_specific;
1361 case PED_PARTITION_RAID:
1362 return gpt_part_data->raid;
1363 case PED_PARTITION_LVM:
1364 return gpt_part_data->lvm;
1365 case PED_PARTITION_BOOT:
1366 return gpt_part_data->boot;
1367 case PED_PARTITION_HPSERVICE:
1368 return gpt_part_data->hp_service;
1369 case PED_PARTITION_MSFT_RESERVED:
1370 return gpt_part_data->msftres;
1371 case PED_PARTITION_HIDDEN:
1372 return gpt_part_data->hidden;
1373 case PED_PARTITION_SWAP:
1374 case PED_PARTITION_LBA:
1375 case PED_PARTITION_ROOT:
1383 gpt_partition_is_flag_available(const PedPartition * part,
1384 PedPartitionFlag flag)
1387 case PED_PARTITION_RAID:
1388 case PED_PARTITION_LVM:
1389 case PED_PARTITION_BOOT:
1390 case PED_PARTITION_HPSERVICE:
1391 case PED_PARTITION_MSFT_RESERVED:
1392 case PED_PARTITION_HIDDEN:
1394 case PED_PARTITION_SWAP:
1395 case PED_PARTITION_ROOT:
1396 case PED_PARTITION_LBA:
1404 gpt_partition_set_name (PedPartition *part, const char *name)
1406 GPTPartitionData *gpt_part_data = part->disk_specific;
1408 strncpy (gpt_part_data->name, name, 36);
1409 gpt_part_data->name [36] = 0;
1413 gpt_partition_get_name (const PedPartition * part)
1415 GPTPartitionData* gpt_part_data = part->disk_specific;
1416 return gpt_part_data->name;
1420 gpt_get_max_primary_partition_count (const PedDisk *disk)
1422 const GPTDiskData* gpt_disk_data = disk->disk_specific;
1423 return gpt_disk_data->entry_count;
1426 static PedConstraint*
1427 _non_metadata_constraint (const PedDisk* disk)
1429 GPTDiskData* gpt_disk_data = disk->disk_specific;
1431 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1435 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1437 PED_ASSERT (part != NULL, return 0);
1439 if (_ped_partition_attempt_align (part, constraint,
1440 _non_metadata_constraint (part->disk)))
1443 #ifndef DISCOVER_ONLY
1444 ped_exception_throw (
1445 PED_EXCEPTION_ERROR,
1446 PED_EXCEPTION_CANCEL,
1447 _("Unable to satisfy all constraints on the partition."));
1452 static PedDiskOps gpt_disk_ops = {
1454 #ifndef DISCOVER_ONLY
1455 clobber: gpt_clobber,
1460 duplicate: gpt_duplicate,
1463 #ifndef DISCOVER_ONLY
1468 partition_new: gpt_partition_new,
1469 partition_duplicate: gpt_partition_duplicate,
1470 partition_destroy: gpt_partition_destroy,
1471 partition_set_system: gpt_partition_set_system,
1472 partition_set_flag: gpt_partition_set_flag,
1473 partition_get_flag: gpt_partition_get_flag,
1474 partition_is_flag_available: gpt_partition_is_flag_available,
1475 partition_set_name: gpt_partition_set_name,
1476 partition_get_name: gpt_partition_get_name,
1477 partition_align: gpt_partition_align,
1478 partition_enumerate: gpt_partition_enumerate,
1479 alloc_metadata: gpt_alloc_metadata,
1480 get_max_primary_partition_count: gpt_get_max_primary_partition_count
1483 static PedDiskType gpt_disk_type = {
1487 features: PED_DISK_TYPE_PARTITION_NAME
1493 PED_ASSERT(sizeof(GuidPartitionEntryAttributes_t) == 8, return);
1494 PED_ASSERT(sizeof(GuidPartitionEntry_t) == 128, return);
1496 ped_register_disk_type(&gpt_disk_type);
1502 ped_unregister_disk_type(&gpt_disk_type);