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>
48 # define _(String) gettext (String)
50 # define _(String) (String)
51 #endif /* ENABLE_NLS */
53 #define EFI_PMBR_OSTYPE_EFI 0xEE
54 #define MSDOS_MBR_SIGNATURE 0xaa55
56 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
58 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
59 * so some implementors got confused...
61 #define GPT_HEADER_REVISION_V1_02 0x00010200
62 #define GPT_HEADER_REVISION_V1_00 0x00010000
63 #define GPT_HEADER_REVISION_V0_99 0x00009900
65 typedef uint16_t efi_char16_t; /* UNICODE character */
66 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
67 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
68 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
69 typedef struct _PartitionRecord_t PartitionRecord_t;
70 typedef struct _LegacyMBR_t LegacyMBR_t;
71 typedef struct _GPTDiskData GPTDiskData;
76 uint16_t time_hi_and_version;
77 uint8_t clock_seq_hi_and_reserved;
78 uint8_t clock_seq_low;
80 } /* __attribute__ ((packed)) */ efi_guid_t;
81 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
82 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
83 * data. It turns out we don't need it in this case, so it doesn't break
87 #define UNUSED_ENTRY_GUID \
88 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
89 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
90 #define PARTITION_SYSTEM_GUID \
91 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
92 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
93 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
94 #define PARTITION_BIOS_GRUB_GUID \
95 ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
96 PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
97 { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
98 #define LEGACY_MBR_PARTITION_GUID \
99 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
100 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
101 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
102 #define PARTITION_MSFT_RESERVED_GUID \
103 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
104 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
105 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
106 #define PARTITION_BASIC_DATA_GUID \
107 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
108 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
109 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
110 #define PARTITION_RAID_GUID \
111 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
112 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
113 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
114 #define PARTITION_SWAP_GUID \
115 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
116 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
117 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
118 #define PARTITION_LVM_GUID \
119 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
120 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
121 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
122 #define PARTITION_RESERVED_GUID \
123 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
124 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
125 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
126 #define PARTITION_HPSERVICE_GUID \
127 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
128 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
129 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
130 #define PARTITION_APPLE_HFS_GUID \
131 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
132 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
133 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
134 #define PARTITION_APPLE_TV_RECOVERY_GUID \
135 ((efi_guid_t) { PED_CPU_TO_LE32 (0x5265636F), PED_CPU_TO_LE16 (0x7665), \
136 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
137 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
139 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
144 uint32_t HeaderCRC32;
147 uint64_t AlternateLBA;
148 uint64_t FirstUsableLBA;
149 uint64_t LastUsableLBA;
151 uint64_t PartitionEntryLBA;
152 uint32_t NumberOfPartitionEntries;
153 uint32_t SizeOfPartitionEntry;
154 uint32_t PartitionEntryArrayCRC32;
158 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
160 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
161 uint64_t RequiredToFunction:1;
162 uint64_t Reserved:47;
163 uint64_t GuidSpecific:16;
165 # warning "Using crippled partition entry type"
166 uint32_t RequiredToFunction:1;
167 uint32_t Reserved:32;
169 uint32_t GuidSpecific:16;
173 struct __attribute__ ((packed)) _GuidPartitionEntry_t
175 efi_guid_t PartitionTypeGuid;
176 efi_guid_t UniquePartitionGuid;
177 uint64_t StartingLBA;
179 GuidPartitionEntryAttributes_t Attributes;
180 efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
183 #define GPT_PMBR_LBA 0
184 #define GPT_PMBR_SECTORS 1
185 #define GPT_PRIMARY_HEADER_LBA 1
186 #define GPT_HEADER_SECTORS 1
187 #define GPT_PRIMARY_PART_TABLE_LBA 2
190 These values are only defaults. The actual on-disk structures
191 may define different sizes, so use those unless creating a new GPT disk!
194 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
196 /* Number of actual partition entries should be calculated as: */
197 #define GPT_DEFAULT_PARTITION_ENTRIES \
198 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
199 sizeof(GuidPartitionEntry_t))
201 struct __attribute__ ((packed)) _PartitionRecord_t
203 /* Not used by EFI firmware. Set to 0x80 to indicate that this
204 is the bootable legacy partition. */
205 uint8_t BootIndicator;
207 /* Start of partition in CHS address, not used by EFI firmware. */
210 /* Start of partition in CHS address, not used by EFI firmware. */
213 /* Start of partition in CHS address, not used by EFI firmware. */
216 /* OS type. A value of 0xEF defines an EFI system partition.
217 Other values are reserved for legacy operating systems, and
218 allocated independently of the EFI specification. */
221 /* End of partition in CHS address, not used by EFI firmware. */
224 /* End of partition in CHS address, not used by EFI firmware. */
227 /* End of partition in CHS address, not used by EFI firmware. */
230 /* Starting LBA address of the partition on the disk. Used by
231 EFI firmware to define the start of the partition. */
232 uint32_t StartingLBA;
234 /* Size of partition in LBA. Used by EFI firmware to determine
235 the size of the partition. */
239 /* Protected Master Boot Record & Legacy MBR share same structure */
240 /* Needs to be packed because the u16s force misalignment. */
241 struct __attribute__ ((packed)) _LegacyMBR_t
243 uint8_t BootCode[440];
244 uint32_t UniqueMBRSignature;
246 PartitionRecord_t PartitionRecord[4];
250 /* uses libparted's disk_specific field in PedDisk, to store our info */
251 struct __attribute__ ((packed)) _GPTDiskData
253 PedGeometry data_area;
258 /* uses libparted's disk_specific field in PedPartition, to store our info */
259 typedef struct _GPTPartitionData
274 static PedDiskType gpt_disk_type;
276 static inline uint32_t
277 pth_get_size (const PedDevice *dev)
279 return GPT_HEADER_SECTORS * dev->sector_size;
282 static inline uint32_t
283 pth_get_size_static (const PedDevice *dev)
285 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
288 static inline uint32_t
289 pth_get_size_rsv2 (const PedDevice *dev)
291 return pth_get_size (dev) - pth_get_size_static (dev);
294 static GuidPartitionTableHeader_t *
295 pth_new (const PedDevice *dev)
297 GuidPartitionTableHeader_t *pth =
298 ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
300 pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
305 static GuidPartitionTableHeader_t *
306 pth_new_zeroed (const PedDevice *dev)
308 GuidPartitionTableHeader_t *pth = pth_new (dev);
310 memset (pth, 0, pth_get_size_static (dev));
311 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
316 static GuidPartitionTableHeader_t *
317 pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
319 GuidPartitionTableHeader_t *pth = pth_new (dev);
321 PED_ASSERT (pth_raw != NULL, return 0);
323 memcpy (pth, pth_raw, pth_get_size_static (dev));
324 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
325 pth_get_size_rsv2 (dev));
331 pth_free (GuidPartitionTableHeader_t *pth)
335 PED_ASSERT (pth->Reserved2 != NULL, return);
337 free (pth->Reserved2);
342 pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
344 PED_ASSERT (pth != NULL, return 0);
345 PED_ASSERT (pth->Reserved2 != NULL, return 0);
347 int size_static = pth_get_size_static (dev);
348 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
352 memcpy (pth_raw, pth, size_static);
353 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
359 * swap_uuid_and_efi_guid() - converts between uuid formats
360 * @uuid - uuid_t in either format (converts it to the other)
362 * There are two different representations for Globally Unique Identifiers
365 * The RFC specifies a UUID as a string of 16 bytes, essentially
366 * a big-endian array of char.
367 * Intel, in their EFI Specification, references the same RFC, but
368 * then defines a GUID as a structure of little-endian fields.
369 * Coincidentally, both structures have the same format when unparsed.
371 * When read from disk, EFI GUIDs are in struct of little endian format,
372 * and need to be converted to be treated as uuid_t in memory.
374 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
379 swap_uuid_and_efi_guid (uuid_t uuid)
381 efi_guid_t *guid = (efi_guid_t *) uuid;
383 PED_ASSERT (uuid != NULL, return);
384 guid->time_low = PED_SWAP32 (guid->time_low);
385 guid->time_mid = PED_SWAP16 (guid->time_mid);
386 guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
389 /* returns the EFI-style CRC32 value for buf
390 * This function uses the crc32 function by Gary S. Brown,
391 * but seeds the function with ~0, and xor's with ~0 at the end.
393 static inline uint32_t
394 efi_crc32 (const void *buf, unsigned long len)
396 return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
399 /* Compute the crc32 checksum of the partition table header
400 and store it in *CRC32. Return 0 upon success. Return 1
401 upon failure to allocate space. */
403 pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth,
406 PED_ASSERT (dev != NULL, return 0);
407 PED_ASSERT (pth != NULL, return 0);
409 uint8_t *pth_raw = pth_get_raw (dev, pth);
413 *crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
420 guid_cmp (efi_guid_t left, efi_guid_t right)
422 return memcmp (&left, &right, sizeof (efi_guid_t));
425 /* checks if 'mbr' is a protective MBR partition table */
427 _pmbr_is_valid (const LegacyMBR_t *mbr)
431 PED_ASSERT (mbr != NULL, return 0);
433 if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
435 for (i = 0; i < 4; i++)
437 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
444 gpt_probe (const PedDevice *dev)
446 GuidPartitionTableHeader_t *gpt = NULL;
447 int gpt_sig_found = 0;
449 PED_ASSERT (dev != NULL, return 0);
451 if (dev->length <= 1)
454 void *pth_raw = ped_malloc (pth_get_size (dev));
455 if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
456 || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
458 gpt = pth_new_from_raw (dev, pth_raw);
459 if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
471 if (!ptt_read_sector (dev, 0, &label))
475 if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
477 int ex_status = ped_exception_throw
478 (PED_EXCEPTION_WARNING,
479 PED_EXCEPTION_YES_NO,
480 _("%s contains GPT signatures, indicating that it has "
481 "a GPT table. However, it does not have a valid "
482 "fake msdos partition table, as it should. Perhaps "
483 "it was corrupted -- possibly by a program that "
484 "doesn't understand GPT partition tables. Or "
485 "perhaps you deleted the GPT table, and are now "
486 "using an msdos partition table. Is this a GPT "
489 if (ex_status == PED_EXCEPTION_NO)
497 #ifndef DISCOVER_ONLY
498 /* writes zeros to the PMBR and the primary GPTH, and to the final sector */
500 gpt_clobber (PedDevice *dev)
502 PED_ASSERT (dev != NULL, return 0);
504 return (ptt_clear_sectors (dev, GPT_PMBR_LBA, GPT_PMBR_SECTORS)
505 && ptt_clear_sectors (dev, GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS)
506 && ptt_clear_sectors (dev, dev->length - GPT_HEADER_SECTORS,
507 GPT_HEADER_SECTORS));
509 #endif /* !DISCOVER_ONLY */
512 gpt_alloc (const PedDevice *dev)
515 GPTDiskData *gpt_disk_data;
516 PedSector data_start, data_end;
518 disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
521 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
522 if (!disk->disk_specific)
523 goto error_free_disk;
525 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
526 data_end = dev->length - 2
527 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
528 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
529 data_end - data_start + 1);
530 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
531 uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
532 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
542 gpt_duplicate (const PedDisk *disk)
545 GPTDiskData *new_disk_data;
546 GPTDiskData *old_disk_data;
548 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
552 old_disk_data = disk->disk_specific;
553 new_disk_data = new_disk->disk_specific;
555 ped_geometry_init (&new_disk_data->data_area, disk->dev,
556 old_disk_data->data_area.start,
557 old_disk_data->data_area.length);
558 new_disk_data->entry_count = old_disk_data->entry_count;
559 new_disk_data->uuid = old_disk_data->uuid;
564 gpt_free (PedDisk *disk)
566 ped_disk_delete_all (disk);
567 free (disk->disk_specific);
568 _ped_disk_free (disk);
571 /* Given GUID Partition table header, GPT, read its partition array
572 entries from DISK into malloc'd storage. Set *PTES_BYTES to the
573 number of bytes required. Upon success, return a pointer to the
574 resulting buffer. Otherwise, set errno and return NULL. */
576 gpt_read_PE_array (PedDisk const *disk, GuidPartitionTableHeader_t const *gpt,
579 GPTDiskData *gpt_disk_data = disk->disk_specific;
580 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
581 *ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
582 size_t ptes_sectors = ped_div_round_up (*ptes_bytes,
583 disk->dev->sector_size);
585 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
590 void *ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
594 if (!ped_device_read (disk->dev, ptes,
595 PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
597 int saved_errno = errno;
607 check_PE_array_CRC (PedDisk const *disk,
608 GuidPartitionTableHeader_t const *gpt, bool *valid)
611 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
615 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
616 *valid = (ptes_crc == PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32));
622 _header_is_valid (PedDisk const *disk, GuidPartitionTableHeader_t *gpt,
625 uint32_t crc, origcrc;
626 PedDevice const *dev = disk->dev;
628 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
631 * "While the GUID Partition Table Header's size may increase
632 * in the future it cannot span more than one block on the
633 * device." EFI Specification, version 1.10, 11.2.2.1
635 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
636 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
639 /* The SizeOfPartitionEntry must be a multiple of 8 and
640 no smaller than the size of the PartitionEntry structure.
641 We also require that be no larger than 1/16th of UINT32_MAX,
642 as an additional sanity check. */
643 uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
645 || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
648 if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
651 PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
652 /* The backup table's AlternateLBA must be 1. */
653 if (my_lba != 1 && alt_lba != 1)
656 /* The alt_lba must never be the same as my_lba. */
657 if (alt_lba == my_lba)
661 if (check_PE_array_CRC (disk, gpt, &crc_match) != 0 || !crc_match)
664 origcrc = gpt->HeaderCRC32;
665 gpt->HeaderCRC32 = 0;
666 if (pth_crc32 (dev, gpt, &crc) != 0)
668 gpt->HeaderCRC32 = origcrc;
670 return crc == PED_LE32_TO_CPU (origcrc);
674 _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
677 GPTDiskData *gpt_disk_data = disk->disk_specific;
678 PedSector first_usable;
679 PedSector last_usable;
680 PedSector last_usable_if_grown, last_usable_min_default;
681 static int asked_already;
683 #ifndef DISCOVER_ONLY
684 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
686 if (ped_exception_throw
687 (PED_EXCEPTION_WARNING,
688 PED_EXCEPTION_IGNORE_CANCEL,
689 _("The format of the GPT partition table is version "
690 "%x, which is newer than what Parted can "
691 "recognise. Please tell us! bug-parted@gnu.org"),
692 PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
697 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
698 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
700 /* Need to check whether the volume has grown, the LastUsableLBA is
701 normally set to disk->dev->length - 2 - ptes_size (at least for parted
702 created volumes), where ptes_size is the number of entries *
703 size of each entry / sector size or 16k / sector size, whatever the greater.
704 If the volume has grown, offer the user the chance to use the new
705 space or continue with the current usable area. Only ask once per
706 parted invocation. */
709 = (disk->dev->length - 2 -
710 ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
711 (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
712 disk->dev->sector_size));
714 last_usable_min_default = disk->dev->length - 2 -
715 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
717 if (last_usable_if_grown > last_usable_min_default)
719 last_usable_if_grown = last_usable_min_default;
722 PED_ASSERT (last_usable > first_usable, return 0);
723 PED_ASSERT (last_usable <= disk->dev->length, return 0);
725 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
726 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
728 if (!asked_already && last_usable < last_usable_if_grown)
731 PedExceptionOption q;
733 q = ped_exception_throw
734 (PED_EXCEPTION_WARNING,
735 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
736 _("Not all of the space available to %s appears "
737 "to be used, you can fix the GPT to use all of the "
738 "space (an extra %llu blocks) or continue with the "
739 "current setting? "), disk->dev->path,
740 (uint64_t) (last_usable_if_grown - last_usable));
742 if (q == PED_EXCEPTION_FIX)
744 last_usable = last_usable_if_grown;
747 else if (q != PED_EXCEPTION_UNHANDLED)
753 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
754 first_usable, last_usable - first_usable + 1);
756 gpt_disk_data->entry_count
757 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
758 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
759 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
761 gpt_disk_data->uuid = gpt->DiskGUID;
766 static PedPartition *
767 _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
770 GPTPartitionData *gpt_part_data;
773 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
774 PED_LE64_TO_CPU (pte->StartingLBA),
775 PED_LE64_TO_CPU (pte->EndingLBA));
779 gpt_part_data = part->disk_specific;
780 gpt_part_data->type = pte->PartitionTypeGuid;
781 gpt_part_data->uuid = pte->UniquePartitionGuid;
782 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
783 gpt_part_data->name[i] =
784 (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
785 gpt_part_data->name[i] = 0;
787 gpt_part_data->lvm = gpt_part_data->raid
788 = gpt_part_data->boot = gpt_part_data->hp_service
789 = gpt_part_data->hidden = gpt_part_data->msftres
790 = gpt_part_data->bios_grub = gpt_part_data->atvrecv = 0;
792 if (pte->Attributes.RequiredToFunction & 0x1)
793 gpt_part_data->hidden = 1;
795 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
796 gpt_part_data->boot = 1;
797 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
798 gpt_part_data->bios_grub = 1;
799 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
800 gpt_part_data->raid = 1;
801 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
802 gpt_part_data->lvm = 1;
803 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
804 gpt_part_data->hp_service = 1;
805 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
806 gpt_part_data->msftres = 1;
807 else if (!guid_cmp (gpt_part_data->type, PARTITION_APPLE_TV_RECOVERY_GUID))
808 gpt_part_data->atvrecv = 1;
813 /* Read the primary GPT at sector 1 of DEV.
814 Verify its CRC and that of its partition entry array.
815 If they are valid, read the backup GPT specified by AlternateLBA.
816 If not, read the backup GPT in the last sector of the disk.
817 Return 1 if any read fails.
818 Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
819 Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
820 If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
821 number in which it was found. */
823 gpt_read_headers (PedDisk const *disk,
824 GuidPartitionTableHeader_t **primary_gpt,
825 GuidPartitionTableHeader_t **backup_gpt,
826 PedSector *backup_sector_num_p)
830 PedDevice const *dev = disk->dev;
833 if (!ptt_read_sector (dev, 1, &s1))
836 GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
840 GuidPartitionTableHeader_t *pri = t;
842 bool valid_primary = _header_is_valid (disk, pri, 1);
848 PedSector backup_sector_num =
850 ? PED_LE64_TO_CPU (pri->AlternateLBA)
854 if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
856 t = pth_new_from_raw (dev, s_bak);
861 GuidPartitionTableHeader_t *bak = t;
862 if (_header_is_valid (disk, bak, backup_sector_num))
865 *backup_sector_num_p = backup_sector_num;
873 /************************************************************
874 * Intel is changing the EFI Spec. (after v1.02) to say that a
875 * disk is considered to have a GPT label only if the GPT
876 * structures are correct, and the MBR is actually a Protective
877 * MBR (has one 0xEE type partition).
878 * Problem occurs when a GPT-partitioned disk is then
879 * edited with a legacy (non-GPT-aware) application, such as
880 * fdisk (which doesn't generally erase the PGPT or AGPT).
881 * How should such a disk get handled? As a GPT disk (throwing
882 * away the fdisk changes), or as an MSDOS disk (throwing away
883 * the GPT information). Previously, I've taken the GPT-is-right,
884 * MBR is wrong, approach, to stay consistent with the EFI Spec.
885 * Intel disagrees, saying the disk should then be treated
886 * as having a msdos label, not a GPT label. If this is true,
887 * then what's the point of having an AGPT, since if the PGPT
888 * is screwed up, likely the PMBR is too, and the PMBR becomes
889 * a single point of failure.
890 * So, in the Linux kernel, I'm going to test for PMBR, and
891 * warn if it's not there, and treat the disk as MSDOS, with a note
892 * for users to use Parted to "fix up" their disk if they
893 * really want it to be considered GPT.
894 ************************************************************/
896 gpt_read (PedDisk *disk)
898 GPTDiskData *gpt_disk_data = disk->disk_specific;
900 #ifndef DISCOVER_ONLY
904 ped_disk_delete_all (disk);
906 /* motivation: let the user decide about the pmbr... during
907 ped_disk_probe(), they probably didn't get a choice... */
908 if (!gpt_probe (disk->dev))
911 GuidPartitionTableHeader_t *gpt = NULL;
912 GuidPartitionTableHeader_t *primary_gpt;
913 GuidPartitionTableHeader_t *backup_gpt;
914 PedSector backup_sector_num;
915 int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
919 /* This includes the case in which there used to be a GPT partition
920 table here, with an alternate LBA that extended beyond the current
921 end-of-device. It's treated as a non-match. */
923 /* Another possibility:
924 The primary header is ok, but backup is corrupt.
925 In the UEFI spec, this means the primary GUID table
926 is officially invalid. */
927 pth_free (backup_gpt);
928 pth_free (primary_gpt);
932 if (primary_gpt && backup_gpt)
934 /* Both are valid. */
935 #ifndef DISCOVER_ONLY
936 if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
938 switch (ped_exception_throw
939 (PED_EXCEPTION_ERROR,
940 (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
941 | PED_EXCEPTION_IGNORE),
942 _("The backup GPT table is not at the end of the disk, as it "
943 "should be. This might mean that another operating system "
944 "believes the disk is smaller. Fix, by moving the backup "
945 "to the end (and removing the old backup)?")))
947 case PED_EXCEPTION_CANCEL:
949 case PED_EXCEPTION_FIX:
950 ptt_clear_sectors (disk->dev,
951 PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
958 #endif /* !DISCOVER_ONLY */
960 pth_free (backup_gpt);
962 else if (!primary_gpt && !backup_gpt)
964 /* Both are corrupt. */
965 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
966 _("Both the primary and backup GPT tables "
967 "are corrupt. Try making a fresh table, "
968 "and using Parted's rescue feature to "
969 "recover partitions."));
972 else if (primary_gpt && !backup_gpt)
974 /* The primary header is ok, but backup is corrupt. */
975 if (ped_exception_throw
976 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
977 _("The backup GPT table is corrupt, but the "
978 "primary appears OK, so that will be used."))
979 == PED_EXCEPTION_CANCEL)
984 else /* !primary_gpt && backup_gpt */
986 /* primary GPT corrupt, backup is ok. */
987 if (ped_exception_throw
988 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
989 _("The primary GPT table is corrupt, but the "
990 "backup appears OK, so that will be used."))
991 == PED_EXCEPTION_CANCEL)
999 if (!_parse_header (disk, gpt, &write_back))
1000 goto error_free_gpt;
1003 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
1005 goto error_free_gpt;
1007 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
1008 if (ptes_crc != PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32))
1011 (PED_EXCEPTION_ERROR,
1012 PED_EXCEPTION_CANCEL,
1013 _("primary partition table array CRC mismatch"));
1014 goto error_free_ptes;
1017 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
1018 for (i = 0; i < gpt_disk_data->entry_count; i++)
1020 GuidPartitionEntry_t *pte
1021 = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
1024 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
1027 part = _parse_part_entry (disk, pte);
1029 goto error_delete_all;
1031 part->fs_type = ped_file_system_probe (&part->geom);
1034 PedConstraint *constraint_exact = ped_constraint_exact (&part->geom);
1035 if (!ped_disk_add_partition (disk, part, constraint_exact))
1037 ped_constraint_destroy (constraint_exact);
1038 ped_partition_destroy (part);
1039 goto error_delete_all;
1041 ped_constraint_destroy (constraint_exact);
1045 #ifndef DISCOVER_ONLY
1047 ped_disk_commit_to_dev (disk);
1054 ped_disk_delete_all (disk);
1058 pth_free (primary_gpt);
1059 pth_free (backup_gpt);
1065 #ifndef DISCOVER_ONLY
1066 /* Write the protective MBR (to keep DOS happy) */
1068 _write_pmbr (PedDevice *dev)
1070 /* The UEFI spec is not clear about what to do with the following
1071 elements of the Protective MBR (pmbr): BootCode (0-440B),
1072 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1073 With this in mind, we try not to modify these elements. */
1075 if (!ptt_read_sector (dev, 0, &s0))
1077 LegacyMBR_t *pmbr = s0;
1079 /* Zero out the legacy partitions. */
1080 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1082 pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1083 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1084 pmbr->PartitionRecord[0].StartSector = 1;
1085 pmbr->PartitionRecord[0].EndHead = 0xFE;
1086 pmbr->PartitionRecord[0].EndSector = 0xFF;
1087 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1088 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1089 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1090 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1092 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1094 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1101 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1102 GuidPartitionTableHeader_t **gpt_p)
1104 GPTDiskData *gpt_disk_data = disk->disk_specific;
1105 GuidPartitionTableHeader_t *gpt;
1107 *gpt_p = pth_new_zeroed (disk->dev);
1111 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1112 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1115 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1116 gpt->HeaderCRC32 = 0;
1121 PedSector ptes_size = gpt_disk_data->entry_count
1122 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1124 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1125 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1126 gpt->PartitionEntryLBA
1127 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1131 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1132 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1133 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1136 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1137 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1138 gpt->DiskGUID = gpt_disk_data->uuid;
1139 gpt->NumberOfPartitionEntries
1140 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1141 gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1142 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1145 if (pth_crc32 (disk->dev, gpt, &crc) != 0)
1148 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
1153 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1155 GPTPartitionData *gpt_part_data = part->disk_specific;
1158 PED_ASSERT (gpt_part_data != NULL, return);
1160 pte->PartitionTypeGuid = gpt_part_data->type;
1161 pte->UniquePartitionGuid = gpt_part_data->uuid;
1162 pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1163 pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1164 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1166 if (gpt_part_data->hidden)
1167 pte->Attributes.RequiredToFunction = 1;
1169 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1170 pte->PartitionName[i]
1171 = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1175 gpt_write (const PedDisk *disk)
1177 GPTDiskData *gpt_disk_data;
1178 GuidPartitionEntry_t *ptes;
1181 GuidPartitionTableHeader_t *gpt;
1185 PED_ASSERT (disk != NULL, goto error);
1186 PED_ASSERT (disk->dev != NULL, goto error);
1187 PED_ASSERT (disk->disk_specific != NULL, goto error);
1189 gpt_disk_data = disk->disk_specific;
1191 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1192 ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1195 memset (ptes, 0, ptes_size);
1196 for (part = ped_disk_next_partition (disk, NULL); part;
1197 part = ped_disk_next_partition (disk, part))
1199 if (part->type != 0)
1201 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1204 ptes_crc = efi_crc32 (ptes, ptes_size);
1206 /* Write protective MBR */
1207 if (!_write_pmbr (disk->dev))
1208 goto error_free_ptes;
1210 /* Write PTH and PTEs */
1211 /* FIXME: Caution: this code is nearly identical to what's just below. */
1212 if (_generate_header (disk, 0, ptes_crc, &gpt) != 0)
1213 goto error_free_ptes;
1214 pth_raw = pth_get_raw (disk->dev, gpt);
1216 if (pth_raw == NULL)
1217 goto error_free_ptes;
1218 int write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1221 goto error_free_ptes;
1222 if (!ped_device_write (disk->dev, ptes, 2,
1223 ptes_size / disk->dev->sector_size))
1224 goto error_free_ptes;
1226 /* Write Alternate PTH & PTEs */
1227 /* FIXME: Caution: this code is nearly identical to what's just above. */
1228 if (_generate_header (disk, 1, ptes_crc, &gpt) != 0)
1229 goto error_free_ptes;
1230 pth_raw = pth_get_raw (disk->dev, gpt);
1232 if (pth_raw == NULL)
1233 goto error_free_ptes;
1234 write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1237 goto error_free_ptes;
1238 if (!ped_device_write (disk->dev, ptes,
1239 disk->dev->length - 1 -
1240 ptes_size / disk->dev->sector_size,
1241 ptes_size / disk->dev->sector_size))
1242 goto error_free_ptes;
1245 return ped_device_sync (disk->dev);
1252 #endif /* !DISCOVER_ONLY */
1255 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1258 PedConstraint *constraint_exact;
1259 PED_ASSERT (disk != NULL, return 0);
1261 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1262 start, start + length - 1);
1266 constraint_exact = ped_constraint_exact (&part->geom);
1267 if (!ped_disk_add_partition (disk, part, constraint_exact))
1268 goto error_destroy_constraint;
1269 ped_constraint_destroy (constraint_exact);
1272 error_destroy_constraint:
1273 ped_constraint_destroy (constraint_exact);
1274 ped_partition_destroy (part);
1279 static PedPartition *
1280 gpt_partition_new (const PedDisk *disk,
1281 PedPartitionType part_type,
1282 const PedFileSystemType *fs_type, PedSector start,
1286 GPTPartitionData *gpt_part_data;
1288 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1295 gpt_part_data = part->disk_specific =
1296 ped_malloc (sizeof (GPTPartitionData));
1298 goto error_free_part;
1300 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1301 gpt_part_data->lvm = 0;
1302 gpt_part_data->raid = 0;
1303 gpt_part_data->boot = 0;
1304 gpt_part_data->bios_grub = 0;
1305 gpt_part_data->hp_service = 0;
1306 gpt_part_data->hidden = 0;
1307 gpt_part_data->msftres = 0;
1308 gpt_part_data->atvrecv = 0;
1309 uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1310 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1311 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1315 _ped_partition_free (part);
1320 static PedPartition *
1321 gpt_partition_duplicate (const PedPartition *part)
1323 PedPartition *result;
1324 GPTPartitionData *part_data = part->disk_specific;
1325 GPTPartitionData *result_data;
1327 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1328 part->geom.start, part->geom.end);
1331 result->num = part->num;
1333 if (result->type != 0)
1336 result_data = result->disk_specific =
1337 ped_malloc (sizeof (GPTPartitionData));
1339 goto error_free_part;
1341 result_data->type = part_data->type;
1342 result_data->uuid = part_data->uuid;
1343 strcpy (result_data->name, part_data->name);
1347 _ped_partition_free (result);
1353 gpt_partition_destroy (PedPartition *part)
1355 if (part->type == 0)
1357 PED_ASSERT (part->disk_specific != NULL, return);
1358 free (part->disk_specific);
1361 _ped_partition_free (part);
1365 gpt_partition_set_system (PedPartition *part,
1366 const PedFileSystemType *fs_type)
1368 GPTPartitionData *gpt_part_data = part->disk_specific;
1370 PED_ASSERT (gpt_part_data != NULL, return 0);
1372 part->fs_type = fs_type;
1374 if (gpt_part_data->lvm)
1376 gpt_part_data->type = PARTITION_LVM_GUID;
1379 if (gpt_part_data->raid)
1381 gpt_part_data->type = PARTITION_RAID_GUID;
1384 if (gpt_part_data->boot)
1386 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1389 if (gpt_part_data->bios_grub)
1391 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1394 if (gpt_part_data->hp_service)
1396 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1399 if (gpt_part_data->msftres)
1401 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1404 if (gpt_part_data->atvrecv)
1406 gpt_part_data->type = PARTITION_APPLE_TV_RECOVERY_GUID;
1412 if (strncmp (fs_type->name, "fat", 3) == 0
1413 || strcmp (fs_type->name, "ntfs") == 0)
1415 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1418 if (strncmp (fs_type->name, "hfs", 3) == 0)
1420 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1423 if (strstr (fs_type->name, "swap"))
1425 gpt_part_data->type = PARTITION_SWAP_GUID;
1430 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1434 /* Allocate metadata partitions for the GPTH and PTES */
1436 gpt_alloc_metadata (PedDisk *disk)
1438 PedSector gptlength, pteslength = 0;
1439 GPTDiskData *gpt_disk_data;
1441 PED_ASSERT (disk != NULL, return 0);
1442 PED_ASSERT (disk->dev != NULL, return 0);
1443 PED_ASSERT (disk->disk_specific != NULL, return 0);
1444 gpt_disk_data = disk->disk_specific;
1446 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1447 disk->dev->sector_size);
1448 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1449 * sizeof (GuidPartitionEntry_t),
1450 disk->dev->sector_size);
1452 /* metadata at the start of the disk includes the MBR */
1453 if (!add_metadata_part (disk, GPT_PMBR_LBA,
1454 GPT_PMBR_SECTORS + gptlength + pteslength))
1457 /* metadata at the end of the disk */
1458 if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1459 gptlength + pteslength))
1465 /* Does nothing, as the read/new/destroy functions maintain part->num */
1467 gpt_partition_enumerate (PedPartition *part)
1469 GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1472 /* never change the partition numbers */
1473 if (part->num != -1)
1476 for (i = 1; i <= gpt_disk_data->entry_count; i++)
1478 if (!ped_disk_get_partition (part->disk, i))
1485 PED_ASSERT (0, return 0);
1487 return 0; /* used if debug is disabled */
1491 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1493 GPTPartitionData *gpt_part_data;
1494 PED_ASSERT (part != NULL, return 0);
1495 PED_ASSERT (part->disk_specific != NULL, return 0);
1496 gpt_part_data = part->disk_specific;
1500 case PED_PARTITION_BOOT:
1501 gpt_part_data->boot = state;
1504 = gpt_part_data->lvm
1505 = gpt_part_data->bios_grub
1506 = gpt_part_data->hp_service
1507 = gpt_part_data->msftres
1508 = gpt_part_data->atvrecv = 0;
1509 return gpt_partition_set_system (part, part->fs_type);
1510 case PED_PARTITION_BIOS_GRUB:
1511 gpt_part_data->bios_grub = state;
1514 = gpt_part_data->lvm
1515 = gpt_part_data->boot
1516 = gpt_part_data->hp_service
1517 = gpt_part_data->msftres
1518 = gpt_part_data->atvrecv = 0;
1519 return gpt_partition_set_system (part, part->fs_type);
1520 case PED_PARTITION_RAID:
1521 gpt_part_data->raid = state;
1524 = gpt_part_data->lvm
1525 = gpt_part_data->bios_grub
1526 = gpt_part_data->hp_service
1527 = gpt_part_data->msftres
1528 = gpt_part_data->atvrecv = 0;
1529 return gpt_partition_set_system (part, part->fs_type);
1530 case PED_PARTITION_LVM:
1531 gpt_part_data->lvm = state;
1534 = gpt_part_data->raid
1535 = gpt_part_data->bios_grub
1536 = gpt_part_data->hp_service
1537 = gpt_part_data->msftres
1538 = gpt_part_data->atvrecv = 0;
1539 return gpt_partition_set_system (part, part->fs_type);
1540 case PED_PARTITION_HPSERVICE:
1541 gpt_part_data->hp_service = state;
1544 = gpt_part_data->raid
1545 = gpt_part_data->lvm
1546 = gpt_part_data->bios_grub
1547 = gpt_part_data->msftres
1548 = gpt_part_data->atvrecv = 0;
1549 return gpt_partition_set_system (part, part->fs_type);
1550 case PED_PARTITION_MSFT_RESERVED:
1551 gpt_part_data->msftres = state;
1554 = gpt_part_data->raid
1555 = gpt_part_data->lvm
1556 = gpt_part_data->bios_grub
1557 = gpt_part_data->hp_service
1558 = gpt_part_data->atvrecv = 0;
1559 return gpt_partition_set_system (part, part->fs_type);
1560 case PED_PARTITION_APPLE_TV_RECOVERY:
1561 gpt_part_data->atvrecv = state;
1564 = gpt_part_data->raid
1565 = gpt_part_data->lvm
1566 = gpt_part_data->bios_grub
1567 = gpt_part_data->hp_service
1568 = gpt_part_data->msftres = 0;
1569 return gpt_partition_set_system (part, part->fs_type);
1570 case PED_PARTITION_HIDDEN:
1571 gpt_part_data->hidden = state;
1573 case PED_PARTITION_SWAP:
1574 case PED_PARTITION_ROOT:
1575 case PED_PARTITION_LBA:
1583 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1585 GPTPartitionData *gpt_part_data;
1586 PED_ASSERT (part->disk_specific != NULL, return 0);
1587 gpt_part_data = part->disk_specific;
1591 case PED_PARTITION_RAID:
1592 return gpt_part_data->raid;
1593 case PED_PARTITION_LVM:
1594 return gpt_part_data->lvm;
1595 case PED_PARTITION_BOOT:
1596 return gpt_part_data->boot;
1597 case PED_PARTITION_BIOS_GRUB:
1598 return gpt_part_data->bios_grub;
1599 case PED_PARTITION_HPSERVICE:
1600 return gpt_part_data->hp_service;
1601 case PED_PARTITION_MSFT_RESERVED:
1602 return gpt_part_data->msftres;
1603 case PED_PARTITION_APPLE_TV_RECOVERY:
1604 return gpt_part_data->atvrecv;
1605 case PED_PARTITION_HIDDEN:
1606 return gpt_part_data->hidden;
1607 case PED_PARTITION_SWAP:
1608 case PED_PARTITION_LBA:
1609 case PED_PARTITION_ROOT:
1617 gpt_partition_is_flag_available (const PedPartition *part,
1618 PedPartitionFlag flag)
1622 case PED_PARTITION_RAID:
1623 case PED_PARTITION_LVM:
1624 case PED_PARTITION_BOOT:
1625 case PED_PARTITION_BIOS_GRUB:
1626 case PED_PARTITION_HPSERVICE:
1627 case PED_PARTITION_MSFT_RESERVED:
1628 case PED_PARTITION_APPLE_TV_RECOVERY:
1629 case PED_PARTITION_HIDDEN:
1631 case PED_PARTITION_SWAP:
1632 case PED_PARTITION_ROOT:
1633 case PED_PARTITION_LBA:
1641 gpt_partition_set_name (PedPartition *part, const char *name)
1643 GPTPartitionData *gpt_part_data = part->disk_specific;
1645 strncpy (gpt_part_data->name, name, 36);
1646 gpt_part_data->name[36] = 0;
1650 gpt_partition_get_name (const PedPartition *part)
1652 GPTPartitionData *gpt_part_data = part->disk_specific;
1653 return gpt_part_data->name;
1657 gpt_get_max_primary_partition_count (const PedDisk *disk)
1659 const GPTDiskData *gpt_disk_data = disk->disk_specific;
1660 return gpt_disk_data->entry_count;
1664 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1665 * According to the specs the first LBA (LBA0) is not relevant (it exists
1666 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1667 * header. The header is as big as the block size. After the header we
1668 * find the Entry array. Each element of said array, describes each
1669 * partition. One can have as much elements as can fit between the end of
1670 * the second LBA (where the header ends) and the FirstUsableLBA.
1671 * FirstUsableLBA is the first logical block that is used for contents
1672 * and is defined in header.
1674 * /---------------------------------------------------\
1675 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1677 * \---------------------------------------------------/
1679 * /----------/ \----------\
1680 * /-----------------------------------------\
1681 * | E1 | E2 | E3 |...............| EN |
1682 * \-----------------------------------------/
1684 * The number of possible partitions or supported partitions is:
1685 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1686 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1689 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1691 GuidPartitionTableHeader_t *pth = NULL;
1692 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1694 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1695 || ped_device_read (disk->dev, pth_raw,
1696 disk->dev->length, GPT_HEADER_SECTORS))
1697 pth = pth_new_from_raw (disk->dev, pth_raw);
1703 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1704 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1709 static PedConstraint *
1710 _non_metadata_constraint (const PedDisk *disk)
1712 GPTDiskData *gpt_disk_data = disk->disk_specific;
1714 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1718 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1720 PED_ASSERT (part != NULL, return 0);
1722 if (_ped_partition_attempt_align (part, constraint,
1723 _non_metadata_constraint (part->disk)))
1726 #ifndef DISCOVER_ONLY
1727 ped_exception_throw (PED_EXCEPTION_ERROR,
1728 PED_EXCEPTION_CANCEL,
1729 _("Unable to satisfy all constraints on the partition."));
1734 #include "pt-common.h"
1735 PT_define_limit_functions (gpt)
1737 static PedDiskOps gpt_disk_ops =
1739 clobber: NULL_IF_DISCOVER_ONLY (gpt_clobber),
1740 write: NULL_IF_DISCOVER_ONLY (gpt_write),
1742 partition_set_name: gpt_partition_set_name,
1743 partition_get_name: gpt_partition_get_name,
1745 PT_op_function_initializers (gpt)
1748 static PedDiskType gpt_disk_type =
1753 features: PED_DISK_TYPE_PARTITION_NAME
1757 ped_disk_gpt_init ()
1759 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1760 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1762 ped_disk_type_register (&gpt_disk_type);
1766 ped_disk_gpt_done ()
1768 ped_disk_type_unregister (&gpt_disk_type);