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-2003, 2005-2010 Free Software Foundation, Inc.
9 EFI GUID Partition Table handling
10 Per Intel EFI Specification v1.02
11 http://developer.intel.com/technology/efi/efi.htm
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 3 of the License, or
16 (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 #include <parted/parted.h>
30 #include <parted/debug.h>
31 #include <parted/endian.h>
32 #include <parted/crc32.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
39 #include <uuid/uuid.h>
49 # define _(String) gettext (String)
51 # define _(String) (String)
52 #endif /* ENABLE_NLS */
54 #define EFI_PMBR_OSTYPE_EFI 0xEE
55 #define MSDOS_MBR_SIGNATURE 0xaa55
57 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
59 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
60 * so some implementors got confused...
62 #define GPT_HEADER_REVISION_V1_02 0x00010200
63 #define GPT_HEADER_REVISION_V1_00 0x00010000
64 #define GPT_HEADER_REVISION_V0_99 0x00009900
66 typedef uint16_t efi_char16_t; /* UNICODE character */
67 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
68 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
69 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
70 typedef struct _PartitionRecord_t PartitionRecord_t;
71 typedef struct _LegacyMBR_t LegacyMBR_t;
72 typedef struct _GPTDiskData GPTDiskData;
79 uint16_t time_hi_and_version;
80 uint8_t clock_seq_hi_and_reserved;
81 uint8_t clock_seq_low;
83 } /* __attribute__ ((packed)) */ efi_guid_t;
84 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
85 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
86 * data. It turns out we don't need it in this case, so it doesn't break
90 #define UNUSED_ENTRY_GUID \
91 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
92 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
93 #define PARTITION_SYSTEM_GUID \
94 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
95 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
96 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
97 #define PARTITION_BIOS_GRUB_GUID \
98 ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
99 PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
100 { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
101 #define LEGACY_MBR_PARTITION_GUID \
102 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
103 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
104 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
105 #define PARTITION_MSFT_RESERVED_GUID \
106 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
107 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
108 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
109 #define PARTITION_MSFT_RECOVERY \
110 ((efi_guid_t) { PED_CPU_TO_LE32 (0xDE94BBA4), PED_CPU_TO_LE16 (0x06D1), \
111 PED_CPU_TO_LE16 (0x4D40), 0xA1, 0x6A, \
112 { 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC }})
113 #define PARTITION_BASIC_DATA_GUID \
114 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
115 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
116 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
117 #define PARTITION_RAID_GUID \
118 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
119 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
120 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
121 #define PARTITION_SWAP_GUID \
122 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
123 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
124 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
125 #define PARTITION_LVM_GUID \
126 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
127 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
128 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
129 #define PARTITION_RESERVED_GUID \
130 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
131 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
132 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
133 #define PARTITION_HPSERVICE_GUID \
134 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
135 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
136 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
137 #define PARTITION_APPLE_HFS_GUID \
138 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
139 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
140 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
141 #define PARTITION_APPLE_TV_RECOVERY_GUID \
142 ((efi_guid_t) { PED_CPU_TO_LE32 (0x5265636F), PED_CPU_TO_LE16 (0x7665), \
143 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
144 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
146 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
151 uint32_t HeaderCRC32;
154 uint64_t AlternateLBA;
155 uint64_t FirstUsableLBA;
156 uint64_t LastUsableLBA;
158 uint64_t PartitionEntryLBA;
159 uint32_t NumberOfPartitionEntries;
160 uint32_t SizeOfPartitionEntry;
161 uint32_t PartitionEntryArrayCRC32;
165 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
167 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
168 uint64_t RequiredToFunction:1;
169 uint64_t NoBlockIOProtocol:1;
170 uint64_t LegacyBIOSBootable:1;
171 uint64_t Reserved:45;
172 uint64_t GuidSpecific:16;
174 # warning "Using crippled partition entry type"
175 uint32_t RequiredToFunction:1;
176 uint32_t NoBlockIOProtocol:1;
177 uint32_t LegacyBIOSBootable:1;
178 uint32_t Reserved:30;
180 uint32_t GuidSpecific:16;
184 struct __attribute__ ((packed)) _GuidPartitionEntry_t
186 efi_guid_t PartitionTypeGuid;
187 efi_guid_t UniquePartitionGuid;
188 uint64_t StartingLBA;
190 GuidPartitionEntryAttributes_t Attributes;
191 efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
194 #define GPT_PMBR_LBA 0
195 #define GPT_PMBR_SECTORS 1
196 #define GPT_PRIMARY_HEADER_LBA 1
197 #define GPT_HEADER_SECTORS 1
198 #define GPT_PRIMARY_PART_TABLE_LBA 2
201 These values are only defaults. The actual on-disk structures
202 may define different sizes, so use those unless creating a new GPT disk!
205 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
207 /* Number of actual partition entries should be calculated as: */
208 #define GPT_DEFAULT_PARTITION_ENTRIES \
209 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
210 sizeof(GuidPartitionEntry_t))
212 struct __attribute__ ((packed)) _PartitionRecord_t
214 /* Not used by EFI firmware. Set to 0x80 to indicate that this
215 is the bootable legacy partition. */
216 uint8_t BootIndicator;
218 /* Start of partition in CHS address, not used by EFI firmware. */
221 /* Start of partition in CHS address, not used by EFI firmware. */
224 /* Start of partition in CHS address, not used by EFI firmware. */
227 /* OS type. A value of 0xEF defines an EFI system partition.
228 Other values are reserved for legacy operating systems, and
229 allocated independently of the EFI specification. */
232 /* End of partition in CHS address, not used by EFI firmware. */
235 /* End of partition in CHS address, not used by EFI firmware. */
238 /* End of partition in CHS address, not used by EFI firmware. */
241 /* Starting LBA address of the partition on the disk. Used by
242 EFI firmware to define the start of the partition. */
243 uint32_t StartingLBA;
245 /* Size of partition in LBA. Used by EFI firmware to determine
246 the size of the partition. */
250 /* Protected Master Boot Record & Legacy MBR share same structure */
251 /* Needs to be packed because the u16s force misalignment. */
252 struct __attribute__ ((packed)) _LegacyMBR_t
254 uint8_t BootCode[440];
255 uint32_t UniqueMBRSignature;
257 PartitionRecord_t PartitionRecord[4];
261 /* uses libparted's disk_specific field in PedDisk, to store our info */
262 struct __attribute__ ((packed)) _GPTDiskData
264 PedGeometry data_area;
269 /* uses libparted's disk_specific field in PedPartition, to store our info */
270 typedef struct _GPTPartitionData
286 static PedDiskType gpt_disk_type;
288 static inline uint32_t
289 pth_get_size (const PedDevice *dev)
291 return GPT_HEADER_SECTORS * dev->sector_size;
294 static inline uint32_t
295 pth_get_size_static (const PedDevice *dev)
297 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
300 static inline uint32_t
301 pth_get_size_rsv2 (const PedDevice *dev)
303 return pth_get_size (dev) - pth_get_size_static (dev);
306 static GuidPartitionTableHeader_t *
307 pth_new (const PedDevice *dev)
309 GuidPartitionTableHeader_t *pth =
310 ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
312 pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
317 static GuidPartitionTableHeader_t *
318 pth_new_zeroed (const PedDevice *dev)
320 GuidPartitionTableHeader_t *pth = pth_new (dev);
322 memset (pth, 0, pth_get_size_static (dev));
323 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
328 static GuidPartitionTableHeader_t *
329 pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
331 GuidPartitionTableHeader_t *pth = pth_new (dev);
333 PED_ASSERT (pth_raw != NULL, return 0);
335 memcpy (pth, pth_raw, pth_get_size_static (dev));
336 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
337 pth_get_size_rsv2 (dev));
343 pth_free (GuidPartitionTableHeader_t *pth)
347 PED_ASSERT (pth->Reserved2 != NULL, return);
349 free (pth->Reserved2);
354 pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
356 PED_ASSERT (pth != NULL, return 0);
357 PED_ASSERT (pth->Reserved2 != NULL, return 0);
359 int size_static = pth_get_size_static (dev);
360 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
364 memcpy (pth_raw, pth, size_static);
365 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
371 * swap_uuid_and_efi_guid() - converts between uuid formats
372 * @uuid - uuid_t in either format (converts it to the other)
374 * There are two different representations for Globally Unique Identifiers
377 * The RFC specifies a UUID as a string of 16 bytes, essentially
378 * a big-endian array of char.
379 * Intel, in their EFI Specification, references the same RFC, but
380 * then defines a GUID as a structure of little-endian fields.
381 * Coincidentally, both structures have the same format when unparsed.
383 * When read from disk, EFI GUIDs are in struct of little endian format,
384 * and need to be converted to be treated as uuid_t in memory.
386 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
391 swap_uuid_and_efi_guid (uuid_t uuid)
393 efi_guid_t *guid = (efi_guid_t *) uuid;
395 PED_ASSERT (uuid != NULL, return);
396 guid->time_low = PED_SWAP32 (guid->time_low);
397 guid->time_mid = PED_SWAP16 (guid->time_mid);
398 guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
401 /* returns the EFI-style CRC32 value for buf
402 * This function uses the crc32 function by Gary S. Brown,
403 * but seeds the function with ~0, and xor's with ~0 at the end.
405 static inline uint32_t
406 efi_crc32 (const void *buf, unsigned long len)
408 return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
411 /* Compute the crc32 checksum of the partition table header
412 and store it in *CRC32. Return 0 upon success. Return 1
413 upon failure to allocate space. */
415 pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth,
418 PED_ASSERT (dev != NULL, return 0);
419 PED_ASSERT (pth != NULL, return 0);
421 uint8_t *pth_raw = pth_get_raw (dev, pth);
425 *crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
432 guid_cmp (efi_guid_t left, efi_guid_t right)
434 return memcmp (&left, &right, sizeof (efi_guid_t));
437 /* checks if 'mbr' is a protective MBR partition table */
439 _pmbr_is_valid (const LegacyMBR_t *mbr)
443 PED_ASSERT (mbr != NULL, return 0);
445 if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
447 for (i = 0; i < 4; i++)
449 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
456 gpt_probe (const PedDevice *dev)
458 GuidPartitionTableHeader_t *gpt = NULL;
459 int gpt_sig_found = 0;
461 PED_ASSERT (dev != NULL, return 0);
463 if (dev->length <= 1)
466 void *pth_raw = ped_malloc (pth_get_size (dev));
467 if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
468 || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
470 gpt = pth_new_from_raw (dev, pth_raw);
471 if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
483 if (!ptt_read_sector (dev, 0, &label))
487 if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
489 int ex_status = ped_exception_throw
490 (PED_EXCEPTION_WARNING,
491 PED_EXCEPTION_YES_NO,
492 _("%s contains GPT signatures, indicating that it has "
493 "a GPT table. However, it does not have a valid "
494 "fake msdos partition table, as it should. Perhaps "
495 "it was corrupted -- possibly by a program that "
496 "doesn't understand GPT partition tables. Or "
497 "perhaps you deleted the GPT table, and are now "
498 "using an msdos partition table. Is this a GPT "
501 if (ex_status == PED_EXCEPTION_NO)
510 gpt_alloc (const PedDevice *dev)
513 GPTDiskData *gpt_disk_data;
514 PedSector data_start, data_end;
516 disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
519 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
520 if (!disk->disk_specific)
521 goto error_free_disk;
523 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
524 data_end = dev->length - 2
525 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
526 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
527 data_end - data_start + 1);
528 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
529 uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
530 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
540 gpt_duplicate (const PedDisk *disk)
543 GPTDiskData *new_disk_data;
544 GPTDiskData *old_disk_data;
546 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
550 old_disk_data = disk->disk_specific;
551 new_disk_data = new_disk->disk_specific;
553 ped_geometry_init (&new_disk_data->data_area, disk->dev,
554 old_disk_data->data_area.start,
555 old_disk_data->data_area.length);
556 new_disk_data->entry_count = old_disk_data->entry_count;
557 new_disk_data->uuid = old_disk_data->uuid;
562 gpt_free (PedDisk *disk)
564 ped_disk_delete_all (disk);
565 free (disk->disk_specific);
566 _ped_disk_free (disk);
569 /* Given GUID Partition table header, GPT, read its partition array
570 entries from DISK into malloc'd storage. Set *PTES_BYTES to the
571 number of bytes required. Upon success, return a pointer to the
572 resulting buffer. Otherwise, set errno and return NULL. */
574 gpt_read_PE_array (PedDisk const *disk, GuidPartitionTableHeader_t const *gpt,
577 GPTDiskData *gpt_disk_data = disk->disk_specific;
578 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
579 *ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
580 size_t ptes_sectors = ped_div_round_up (*ptes_bytes,
581 disk->dev->sector_size);
583 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
588 void *ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
592 if (!ped_device_read (disk->dev, ptes,
593 PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
595 int saved_errno = errno;
605 check_PE_array_CRC (PedDisk const *disk,
606 GuidPartitionTableHeader_t const *gpt, bool *valid)
609 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
613 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
614 *valid = (ptes_crc == PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32));
620 _header_is_valid (PedDisk const *disk, GuidPartitionTableHeader_t *gpt,
623 uint32_t crc, origcrc;
624 PedDevice const *dev = disk->dev;
626 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
629 * "While the GUID Partition Table Header's size may increase
630 * in the future it cannot span more than one block on the
631 * device." EFI Specification, version 1.10, 11.2.2.1
633 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
634 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
637 /* The SizeOfPartitionEntry must be a multiple of 8 and
638 no smaller than the size of the PartitionEntry structure.
639 We also require that be no larger than 1/16th of UINT32_MAX,
640 as an additional sanity check. */
641 uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
643 || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
646 if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
649 PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
650 /* The backup table's AlternateLBA must be 1. */
651 if (my_lba != 1 && alt_lba != 1)
654 /* The alt_lba must never be the same as my_lba. */
655 if (alt_lba == my_lba)
659 if (check_PE_array_CRC (disk, gpt, &crc_match) != 0 || !crc_match)
662 origcrc = gpt->HeaderCRC32;
663 gpt->HeaderCRC32 = 0;
664 if (pth_crc32 (dev, gpt, &crc) != 0)
666 gpt->HeaderCRC32 = origcrc;
668 return crc == PED_LE32_TO_CPU (origcrc);
672 _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
675 GPTDiskData *gpt_disk_data = disk->disk_specific;
676 PedSector first_usable;
677 PedSector last_usable;
678 PedSector last_usable_if_grown, last_usable_min_default;
679 static int asked_already;
681 #ifndef DISCOVER_ONLY
682 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
684 if (ped_exception_throw
685 (PED_EXCEPTION_WARNING,
686 PED_EXCEPTION_IGNORE_CANCEL,
687 _("The format of the GPT partition table is version "
688 "%x, which is newer than what Parted can "
689 "recognise. Please report this!"),
690 PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
695 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
696 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
698 /* Need to check whether the volume has grown, the LastUsableLBA is
699 normally set to disk->dev->length - 2 - ptes_size (at least for parted
700 created volumes), where ptes_size is the number of entries *
701 size of each entry / sector size or 16k / sector size, whatever the greater.
702 If the volume has grown, offer the user the chance to use the new
703 space or continue with the current usable area. Only ask once per
704 parted invocation. */
707 = (disk->dev->length - 2 -
708 ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
709 (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
710 disk->dev->sector_size));
712 last_usable_min_default = disk->dev->length - 2 -
713 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
715 if (last_usable_if_grown > last_usable_min_default)
717 last_usable_if_grown = last_usable_min_default;
720 PED_ASSERT (last_usable > first_usable, return 0);
721 PED_ASSERT (last_usable <= disk->dev->length, return 0);
723 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
724 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
726 if (!asked_already && last_usable < last_usable_if_grown)
729 PedExceptionOption q;
731 q = ped_exception_throw
732 (PED_EXCEPTION_WARNING,
733 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
734 _("Not all of the space available to %s appears "
735 "to be used, you can fix the GPT to use all of the "
736 "space (an extra %llu blocks) or continue with the "
737 "current setting? "), disk->dev->path,
738 (uint64_t) (last_usable_if_grown - last_usable));
740 if (q == PED_EXCEPTION_FIX)
742 last_usable = last_usable_if_grown;
745 else if (q != PED_EXCEPTION_UNHANDLED)
751 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
752 first_usable, last_usable - first_usable + 1);
754 gpt_disk_data->entry_count
755 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
756 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
757 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
759 gpt_disk_data->uuid = gpt->DiskGUID;
764 static PedPartition *
765 _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
768 GPTPartitionData *gpt_part_data;
771 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
772 PED_LE64_TO_CPU (pte->StartingLBA),
773 PED_LE64_TO_CPU (pte->EndingLBA));
777 gpt_part_data = part->disk_specific;
778 gpt_part_data->type = pte->PartitionTypeGuid;
779 gpt_part_data->uuid = pte->UniquePartitionGuid;
780 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
781 gpt_part_data->name[i] =
782 (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
783 gpt_part_data->name[i] = 0;
785 gpt_part_data->lvm = gpt_part_data->raid
786 = gpt_part_data->boot = gpt_part_data->hp_service
787 = gpt_part_data->hidden = gpt_part_data->msftres
788 = gpt_part_data->msftrecv
789 = gpt_part_data->bios_grub = gpt_part_data->atvrecv = 0;
791 if (pte->Attributes.RequiredToFunction & 0x1)
792 gpt_part_data->hidden = 1;
794 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
795 gpt_part_data->boot = 1;
796 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
797 gpt_part_data->bios_grub = 1;
798 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
799 gpt_part_data->raid = 1;
800 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
801 gpt_part_data->lvm = 1;
802 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
803 gpt_part_data->hp_service = 1;
804 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
805 gpt_part_data->msftres = 1;
806 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RECOVERY))
807 gpt_part_data->msftrecv = 1;
808 else if (!guid_cmp (gpt_part_data->type, PARTITION_APPLE_TV_RECOVERY_GUID))
809 gpt_part_data->atvrecv = 1;
814 /* Read the primary GPT at sector 1 of DEV.
815 Verify its CRC and that of its partition entry array.
816 If they are valid, read the backup GPT specified by AlternateLBA.
817 If not, read the backup GPT in the last sector of the disk.
818 Return 1 if any read fails.
819 Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
820 Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
821 If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
822 number in which it was found. */
824 gpt_read_headers (PedDisk const *disk,
825 GuidPartitionTableHeader_t **primary_gpt,
826 GuidPartitionTableHeader_t **backup_gpt,
827 PedSector *backup_sector_num_p)
831 PedDevice const *dev = disk->dev;
834 if (!ptt_read_sector (dev, 1, &s1))
837 GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
841 GuidPartitionTableHeader_t *pri = t;
843 bool valid_primary = _header_is_valid (disk, pri, 1);
849 PedSector backup_sector_num =
851 ? PED_LE64_TO_CPU (pri->AlternateLBA)
855 if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
857 t = pth_new_from_raw (dev, s_bak);
862 GuidPartitionTableHeader_t *bak = t;
863 if (_header_is_valid (disk, bak, backup_sector_num))
866 *backup_sector_num_p = backup_sector_num;
874 /************************************************************
875 * Intel is changing the EFI Spec. (after v1.02) to say that a
876 * disk is considered to have a GPT label only if the GPT
877 * structures are correct, and the MBR is actually a Protective
878 * MBR (has one 0xEE type partition).
879 * Problem occurs when a GPT-partitioned disk is then
880 * edited with a legacy (non-GPT-aware) application, such as
881 * fdisk (which doesn't generally erase the PGPT or AGPT).
882 * How should such a disk get handled? As a GPT disk (throwing
883 * away the fdisk changes), or as an MSDOS disk (throwing away
884 * the GPT information). Previously, I've taken the GPT-is-right,
885 * MBR is wrong, approach, to stay consistent with the EFI Spec.
886 * Intel disagrees, saying the disk should then be treated
887 * as having a msdos label, not a GPT label. If this is true,
888 * then what's the point of having an AGPT, since if the PGPT
889 * is screwed up, likely the PMBR is too, and the PMBR becomes
890 * a single point of failure.
891 * So, in the Linux kernel, I'm going to test for PMBR, and
892 * warn if it's not there, and treat the disk as MSDOS, with a note
893 * for users to use Parted to "fix up" their disk if they
894 * really want it to be considered GPT.
895 ************************************************************/
897 gpt_read (PedDisk *disk)
899 GPTDiskData *gpt_disk_data = disk->disk_specific;
901 #ifndef DISCOVER_ONLY
905 ped_disk_delete_all (disk);
907 /* motivation: let the user decide about the pmbr... during
908 ped_disk_probe(), they probably didn't get a choice... */
909 if (!gpt_probe (disk->dev))
912 GuidPartitionTableHeader_t *gpt = NULL;
913 GuidPartitionTableHeader_t *primary_gpt;
914 GuidPartitionTableHeader_t *backup_gpt;
915 PedSector backup_sector_num;
916 int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
920 /* This includes the case in which there used to be a GPT partition
921 table here, with an alternate LBA that extended beyond the current
922 end-of-device. It's treated as a non-match. */
924 /* Another possibility:
925 The primary header is ok, but backup is corrupt.
926 In the UEFI spec, this means the primary GUID table
927 is officially invalid. */
928 pth_free (backup_gpt);
929 pth_free (primary_gpt);
933 if (primary_gpt && backup_gpt)
935 /* Both are valid. */
936 #ifndef DISCOVER_ONLY
937 if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
939 switch (ped_exception_throw
940 (PED_EXCEPTION_ERROR,
941 (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
942 | PED_EXCEPTION_IGNORE),
943 _("The backup GPT table is not at the end of the disk, as it "
944 "should be. This might mean that another operating system "
945 "believes the disk is smaller. Fix, by moving the backup "
946 "to the end (and removing the old backup)?")))
948 case PED_EXCEPTION_CANCEL:
950 case PED_EXCEPTION_FIX:
951 ptt_clear_sectors (disk->dev,
952 PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
959 #endif /* !DISCOVER_ONLY */
961 pth_free (backup_gpt);
963 else if (!primary_gpt && !backup_gpt)
965 /* Both are corrupt. */
966 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
967 _("Both the primary and backup GPT tables "
968 "are corrupt. Try making a fresh table, "
969 "and using Parted's rescue feature to "
970 "recover partitions."));
973 else if (primary_gpt && !backup_gpt)
975 /* The primary header is ok, but backup is corrupt. */
976 if (ped_exception_throw
977 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
978 _("The backup GPT table is corrupt, but the "
979 "primary appears OK, so that will be used."))
980 == PED_EXCEPTION_CANCEL)
985 else /* !primary_gpt && backup_gpt */
987 /* primary GPT corrupt, backup is ok. */
988 if (ped_exception_throw
989 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
990 _("The primary GPT table is corrupt, but the "
991 "backup appears OK, so that will be used."))
992 == PED_EXCEPTION_CANCEL)
1000 if (!_parse_header (disk, gpt, &write_back))
1001 goto error_free_gpt;
1004 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
1006 goto error_free_gpt;
1008 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
1009 if (ptes_crc != PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32))
1012 (PED_EXCEPTION_ERROR,
1013 PED_EXCEPTION_CANCEL,
1014 _("primary partition table array CRC mismatch"));
1015 goto error_free_ptes;
1018 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
1019 for (i = 0; i < gpt_disk_data->entry_count; i++)
1021 GuidPartitionEntry_t *pte
1022 = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
1025 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
1028 part = _parse_part_entry (disk, pte);
1030 goto error_delete_all;
1032 part->fs_type = ped_file_system_probe (&part->geom);
1035 PedConstraint *constraint_exact = ped_constraint_exact (&part->geom);
1036 if (!ped_disk_add_partition (disk, part, constraint_exact))
1038 ped_constraint_destroy (constraint_exact);
1039 ped_partition_destroy (part);
1040 goto error_delete_all;
1042 ped_constraint_destroy (constraint_exact);
1046 #ifndef DISCOVER_ONLY
1048 ped_disk_commit_to_dev (disk);
1055 ped_disk_delete_all (disk);
1059 pth_free (primary_gpt);
1060 pth_free (backup_gpt);
1066 #ifndef DISCOVER_ONLY
1067 /* Write the protective MBR (to keep DOS happy) */
1069 _write_pmbr (PedDevice *dev)
1071 /* The UEFI spec is not clear about what to do with the following
1072 elements of the Protective MBR (pmbr): BootCode (0-440B),
1073 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1074 With this in mind, we try not to modify these elements. */
1076 if (!ptt_read_sector (dev, 0, &s0))
1078 LegacyMBR_t *pmbr = s0;
1080 /* Zero out the legacy partitions. */
1081 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1083 pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1084 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1085 pmbr->PartitionRecord[0].StartSector = 1;
1086 pmbr->PartitionRecord[0].EndHead = 0xFE;
1087 pmbr->PartitionRecord[0].EndSector = 0xFF;
1088 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1089 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1090 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1091 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1093 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1095 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1102 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1103 GuidPartitionTableHeader_t **gpt_p)
1105 GPTDiskData *gpt_disk_data = disk->disk_specific;
1106 GuidPartitionTableHeader_t *gpt;
1108 *gpt_p = pth_new_zeroed (disk->dev);
1112 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1113 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1116 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1117 gpt->HeaderCRC32 = 0;
1122 PedSector ptes_size = gpt_disk_data->entry_count
1123 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1125 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1126 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1127 gpt->PartitionEntryLBA
1128 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1132 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1133 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1134 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1137 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1138 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1139 gpt->DiskGUID = gpt_disk_data->uuid;
1140 gpt->NumberOfPartitionEntries
1141 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1142 gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1143 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1146 if (pth_crc32 (disk->dev, gpt, &crc) != 0)
1149 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
1154 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1156 GPTPartitionData *gpt_part_data = part->disk_specific;
1159 PED_ASSERT (gpt_part_data != NULL, return);
1161 pte->PartitionTypeGuid = gpt_part_data->type;
1162 pte->UniquePartitionGuid = gpt_part_data->uuid;
1163 pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1164 pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1165 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1167 if (gpt_part_data->hidden)
1168 pte->Attributes.RequiredToFunction = 1;
1170 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1171 pte->PartitionName[i]
1172 = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1176 gpt_write (const PedDisk *disk)
1178 GPTDiskData *gpt_disk_data;
1179 GuidPartitionEntry_t *ptes;
1182 GuidPartitionTableHeader_t *gpt;
1186 PED_ASSERT (disk != NULL, goto error);
1187 PED_ASSERT (disk->dev != NULL, goto error);
1188 PED_ASSERT (disk->disk_specific != NULL, goto error);
1190 gpt_disk_data = disk->disk_specific;
1192 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1193 ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1196 memset (ptes, 0, ptes_size);
1197 for (part = ped_disk_next_partition (disk, NULL); part;
1198 part = ped_disk_next_partition (disk, part))
1200 if (part->type != 0)
1202 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1205 ptes_crc = efi_crc32 (ptes, ptes_size);
1207 /* Write protective MBR */
1208 if (!_write_pmbr (disk->dev))
1209 goto error_free_ptes;
1211 /* Write PTH and PTEs */
1212 /* FIXME: Caution: this code is nearly identical to what's just below. */
1213 if (_generate_header (disk, 0, ptes_crc, &gpt) != 0)
1214 goto error_free_ptes;
1215 pth_raw = pth_get_raw (disk->dev, gpt);
1217 if (pth_raw == NULL)
1218 goto error_free_ptes;
1219 int write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1222 goto error_free_ptes;
1223 if (!ped_device_write (disk->dev, ptes, 2,
1224 ptes_size / disk->dev->sector_size))
1225 goto error_free_ptes;
1227 /* Write Alternate PTH & PTEs */
1228 /* FIXME: Caution: this code is nearly identical to what's just above. */
1229 if (_generate_header (disk, 1, ptes_crc, &gpt) != 0)
1230 goto error_free_ptes;
1231 pth_raw = pth_get_raw (disk->dev, gpt);
1233 if (pth_raw == NULL)
1234 goto error_free_ptes;
1235 write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1238 goto error_free_ptes;
1239 if (!ped_device_write (disk->dev, ptes,
1240 disk->dev->length - 1 -
1241 ptes_size / disk->dev->sector_size,
1242 ptes_size / disk->dev->sector_size))
1243 goto error_free_ptes;
1246 return ped_device_sync (disk->dev);
1253 #endif /* !DISCOVER_ONLY */
1256 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1259 PedConstraint *constraint_exact;
1260 PED_ASSERT (disk != NULL, return 0);
1262 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1263 start, start + length - 1);
1267 constraint_exact = ped_constraint_exact (&part->geom);
1268 if (!ped_disk_add_partition (disk, part, constraint_exact))
1269 goto error_destroy_constraint;
1270 ped_constraint_destroy (constraint_exact);
1273 error_destroy_constraint:
1274 ped_constraint_destroy (constraint_exact);
1275 ped_partition_destroy (part);
1280 static PedPartition *
1281 gpt_partition_new (const PedDisk *disk,
1282 PedPartitionType part_type,
1283 const PedFileSystemType *fs_type, PedSector start,
1287 GPTPartitionData *gpt_part_data;
1289 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1296 gpt_part_data = part->disk_specific =
1297 ped_malloc (sizeof (GPTPartitionData));
1299 goto error_free_part;
1301 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1302 gpt_part_data->lvm = 0;
1303 gpt_part_data->raid = 0;
1304 gpt_part_data->boot = 0;
1305 gpt_part_data->bios_grub = 0;
1306 gpt_part_data->hp_service = 0;
1307 gpt_part_data->hidden = 0;
1308 gpt_part_data->msftres = 0;
1309 gpt_part_data->msftrecv = 0;
1310 gpt_part_data->atvrecv = 0;
1311 uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1312 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1313 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1317 _ped_partition_free (part);
1322 static PedPartition *
1323 gpt_partition_duplicate (const PedPartition *part)
1325 PedPartition *result;
1326 GPTPartitionData *part_data = part->disk_specific;
1327 GPTPartitionData *result_data;
1329 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1330 part->geom.start, part->geom.end);
1333 result->num = part->num;
1335 if (result->type != 0)
1338 result_data = result->disk_specific =
1339 ped_malloc (sizeof (GPTPartitionData));
1341 goto error_free_part;
1343 result_data->type = part_data->type;
1344 result_data->uuid = part_data->uuid;
1345 strcpy (result_data->name, part_data->name);
1349 _ped_partition_free (result);
1355 gpt_partition_destroy (PedPartition *part)
1357 if (part->type == 0)
1359 PED_ASSERT (part->disk_specific != NULL, return);
1360 free (part->disk_specific);
1363 _ped_partition_free (part);
1367 gpt_partition_set_system (PedPartition *part,
1368 const PedFileSystemType *fs_type)
1370 GPTPartitionData *gpt_part_data = part->disk_specific;
1372 PED_ASSERT (gpt_part_data != NULL, return 0);
1374 part->fs_type = fs_type;
1376 if (gpt_part_data->lvm)
1378 gpt_part_data->type = PARTITION_LVM_GUID;
1381 if (gpt_part_data->raid)
1383 gpt_part_data->type = PARTITION_RAID_GUID;
1386 if (gpt_part_data->boot)
1388 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1391 if (gpt_part_data->bios_grub)
1393 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1396 if (gpt_part_data->hp_service)
1398 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1401 if (gpt_part_data->msftres)
1403 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1406 if (gpt_part_data->msftrecv)
1408 gpt_part_data->type = PARTITION_MSFT_RECOVERY;
1411 if (gpt_part_data->atvrecv)
1413 gpt_part_data->type = PARTITION_APPLE_TV_RECOVERY_GUID;
1419 if (strncmp (fs_type->name, "fat", 3) == 0
1420 || strcmp (fs_type->name, "ntfs") == 0)
1422 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1425 if (strncmp (fs_type->name, "hfs", 3) == 0)
1427 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1430 if (strstr (fs_type->name, "swap"))
1432 gpt_part_data->type = PARTITION_SWAP_GUID;
1437 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1441 /* Allocate metadata partitions for the GPTH and PTES */
1443 gpt_alloc_metadata (PedDisk *disk)
1445 PedSector gptlength, pteslength = 0;
1446 GPTDiskData *gpt_disk_data;
1448 PED_ASSERT (disk != NULL, return 0);
1449 PED_ASSERT (disk->dev != NULL, return 0);
1450 PED_ASSERT (disk->disk_specific != NULL, return 0);
1451 gpt_disk_data = disk->disk_specific;
1453 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1454 disk->dev->sector_size);
1455 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1456 * sizeof (GuidPartitionEntry_t),
1457 disk->dev->sector_size);
1459 /* metadata at the start of the disk includes the MBR */
1460 if (!add_metadata_part (disk, GPT_PMBR_LBA,
1461 GPT_PMBR_SECTORS + gptlength + pteslength))
1464 /* metadata at the end of the disk */
1465 if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1466 gptlength + pteslength))
1472 /* Does nothing, as the read/new/destroy functions maintain part->num */
1474 gpt_partition_enumerate (PedPartition *part)
1476 GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1479 /* never change the partition numbers */
1480 if (part->num != -1)
1483 for (i = 1; i <= gpt_disk_data->entry_count; i++)
1485 if (!ped_disk_get_partition (part->disk, i))
1492 PED_ASSERT (0, return 0);
1494 return 0; /* used if debug is disabled */
1498 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1500 GPTPartitionData *gpt_part_data;
1501 PED_ASSERT (part != NULL, return 0);
1502 PED_ASSERT (part->disk_specific != NULL, return 0);
1503 gpt_part_data = part->disk_specific;
1507 case PED_PARTITION_BOOT:
1508 gpt_part_data->boot = state;
1511 = gpt_part_data->lvm
1512 = gpt_part_data->bios_grub
1513 = gpt_part_data->hp_service
1514 = gpt_part_data->msftres
1515 = gpt_part_data->msftrecv
1516 = gpt_part_data->atvrecv = 0;
1517 return gpt_partition_set_system (part, part->fs_type);
1518 case PED_PARTITION_BIOS_GRUB:
1519 gpt_part_data->bios_grub = state;
1522 = gpt_part_data->lvm
1523 = gpt_part_data->boot
1524 = gpt_part_data->hp_service
1525 = gpt_part_data->msftres
1526 = gpt_part_data->msftrecv
1527 = gpt_part_data->atvrecv = 0;
1528 return gpt_partition_set_system (part, part->fs_type);
1529 case PED_PARTITION_RAID:
1530 gpt_part_data->raid = state;
1533 = gpt_part_data->lvm
1534 = gpt_part_data->bios_grub
1535 = gpt_part_data->hp_service
1536 = gpt_part_data->msftres
1537 = gpt_part_data->msftrecv
1538 = gpt_part_data->atvrecv = 0;
1539 return gpt_partition_set_system (part, part->fs_type);
1540 case PED_PARTITION_LVM:
1541 gpt_part_data->lvm = state;
1544 = gpt_part_data->raid
1545 = gpt_part_data->bios_grub
1546 = gpt_part_data->hp_service
1547 = gpt_part_data->msftres
1548 = gpt_part_data->msftrecv
1549 = gpt_part_data->atvrecv = 0;
1550 return gpt_partition_set_system (part, part->fs_type);
1551 case PED_PARTITION_HPSERVICE:
1552 gpt_part_data->hp_service = state;
1555 = gpt_part_data->raid
1556 = gpt_part_data->lvm
1557 = gpt_part_data->bios_grub
1558 = gpt_part_data->msftres
1559 = gpt_part_data->msftrecv
1560 = gpt_part_data->atvrecv = 0;
1561 return gpt_partition_set_system (part, part->fs_type);
1562 case PED_PARTITION_MSFT_RESERVED:
1563 gpt_part_data->msftres = state;
1566 = gpt_part_data->raid
1567 = gpt_part_data->lvm
1568 = gpt_part_data->bios_grub
1569 = gpt_part_data->hp_service
1570 = gpt_part_data->msftrecv
1571 = gpt_part_data->atvrecv = 0;
1572 return gpt_partition_set_system (part, part->fs_type);
1573 case PED_PARTITION_DIAG:
1574 gpt_part_data->msftrecv = state;
1577 = gpt_part_data->raid
1578 = gpt_part_data->lvm
1579 = gpt_part_data->bios_grub
1580 = gpt_part_data->hp_service
1581 = gpt_part_data->msftres
1582 = gpt_part_data->atvrecv = 0;
1583 return gpt_partition_set_system (part, part->fs_type);
1584 case PED_PARTITION_APPLE_TV_RECOVERY:
1585 gpt_part_data->atvrecv = state;
1588 = gpt_part_data->raid
1589 = gpt_part_data->lvm
1590 = gpt_part_data->bios_grub
1591 = gpt_part_data->hp_service
1592 = gpt_part_data->msftres
1593 = gpt_part_data->msftrecv = 0;
1594 return gpt_partition_set_system (part, part->fs_type);
1595 case PED_PARTITION_HIDDEN:
1596 gpt_part_data->hidden = state;
1598 case PED_PARTITION_SWAP:
1599 case PED_PARTITION_ROOT:
1600 case PED_PARTITION_LBA:
1608 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1610 GPTPartitionData *gpt_part_data;
1611 PED_ASSERT (part->disk_specific != NULL, return 0);
1612 gpt_part_data = part->disk_specific;
1616 case PED_PARTITION_RAID:
1617 return gpt_part_data->raid;
1618 case PED_PARTITION_LVM:
1619 return gpt_part_data->lvm;
1620 case PED_PARTITION_BOOT:
1621 return gpt_part_data->boot;
1622 case PED_PARTITION_BIOS_GRUB:
1623 return gpt_part_data->bios_grub;
1624 case PED_PARTITION_HPSERVICE:
1625 return gpt_part_data->hp_service;
1626 case PED_PARTITION_MSFT_RESERVED:
1627 return gpt_part_data->msftres;
1628 case PED_PARTITION_DIAG:
1629 return gpt_part_data->msftrecv;
1630 case PED_PARTITION_APPLE_TV_RECOVERY:
1631 return gpt_part_data->atvrecv;
1632 case PED_PARTITION_HIDDEN:
1633 return gpt_part_data->hidden;
1634 case PED_PARTITION_SWAP:
1635 case PED_PARTITION_LBA:
1636 case PED_PARTITION_ROOT:
1644 gpt_partition_is_flag_available (const PedPartition *part,
1645 PedPartitionFlag flag)
1649 case PED_PARTITION_RAID:
1650 case PED_PARTITION_LVM:
1651 case PED_PARTITION_BOOT:
1652 case PED_PARTITION_BIOS_GRUB:
1653 case PED_PARTITION_HPSERVICE:
1654 case PED_PARTITION_MSFT_RESERVED:
1655 case PED_PARTITION_DIAG:
1656 case PED_PARTITION_APPLE_TV_RECOVERY:
1657 case PED_PARTITION_HIDDEN:
1659 case PED_PARTITION_SWAP:
1660 case PED_PARTITION_ROOT:
1661 case PED_PARTITION_LBA:
1669 gpt_partition_set_name (PedPartition *part, const char *name)
1671 GPTPartitionData *gpt_part_data = part->disk_specific;
1673 strncpy (gpt_part_data->name, name, 36);
1674 gpt_part_data->name[36] = 0;
1678 gpt_partition_get_name (const PedPartition *part)
1680 GPTPartitionData *gpt_part_data = part->disk_specific;
1681 return gpt_part_data->name;
1685 gpt_get_max_primary_partition_count (const PedDisk *disk)
1687 const GPTDiskData *gpt_disk_data = disk->disk_specific;
1688 return gpt_disk_data->entry_count;
1692 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1693 * According to the specs the first LBA (LBA0) is not relevant (it exists
1694 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1695 * header. The header is as big as the block size. After the header we
1696 * find the Entry array. Each element of said array, describes each
1697 * partition. One can have as much elements as can fit between the end of
1698 * the second LBA (where the header ends) and the FirstUsableLBA.
1699 * FirstUsableLBA is the first logical block that is used for contents
1700 * and is defined in header.
1702 * /---------------------------------------------------\
1703 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1705 * \---------------------------------------------------/
1707 * /----------/ \----------\
1708 * /-----------------------------------------\
1709 * | E1 | E2 | E3 |...............| EN |
1710 * \-----------------------------------------/
1712 * The number of possible partitions or supported partitions is:
1713 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1714 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1717 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1719 GuidPartitionTableHeader_t *pth = NULL;
1720 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1722 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1723 || ped_device_read (disk->dev, pth_raw,
1724 disk->dev->length, GPT_HEADER_SECTORS))
1725 pth = pth_new_from_raw (disk->dev, pth_raw);
1731 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1732 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1737 static PedConstraint *
1738 _non_metadata_constraint (const PedDisk *disk)
1740 GPTDiskData *gpt_disk_data = disk->disk_specific;
1742 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1746 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1748 PED_ASSERT (part != NULL, return 0);
1750 if (_ped_partition_attempt_align (part, constraint,
1751 _non_metadata_constraint (part->disk)))
1754 #ifndef DISCOVER_ONLY
1755 ped_exception_throw (PED_EXCEPTION_ERROR,
1756 PED_EXCEPTION_CANCEL,
1757 _("Unable to satisfy all constraints on the partition."));
1762 #include "pt-common.h"
1763 PT_define_limit_functions (gpt)
1765 static PedDiskOps gpt_disk_ops =
1768 write: NULL_IF_DISCOVER_ONLY (gpt_write),
1770 partition_set_name: gpt_partition_set_name,
1771 partition_get_name: gpt_partition_get_name,
1773 PT_op_function_initializers (gpt)
1776 static PedDiskType gpt_disk_type =
1781 features: PED_DISK_TYPE_PARTITION_NAME
1785 ped_disk_gpt_init ()
1787 ped_disk_type_register (&gpt_disk_type);
1791 ped_disk_gpt_done ()
1793 ped_disk_type_unregister (&gpt_disk_type);
1796 verify (sizeof (GuidPartitionEntryAttributes_t) == 8);
1797 verify (sizeof (GuidPartitionEntry_t) == 128);