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);
962 #endif /* !DISCOVER_ONLY */
964 pth_free (backup_gpt);
966 else if (!primary_gpt && !backup_gpt)
968 /* Both are corrupt. */
969 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
970 _("Both the primary and backup GPT tables "
971 "are corrupt. Try making a fresh table, "
972 "and using Parted's rescue feature to "
973 "recover partitions."));
976 else if (primary_gpt && !backup_gpt)
978 /* The primary header is ok, but backup is corrupt. */
979 if (ped_exception_throw
980 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
981 _("The backup GPT table is corrupt, but the "
982 "primary appears OK, so that will be used."))
983 == PED_EXCEPTION_CANCEL)
989 else /* !primary_gpt && backup_gpt */
991 /* primary GPT corrupt, backup is ok. */
992 if (ped_exception_throw
993 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
994 _("The primary GPT table is corrupt, but the "
995 "backup appears OK, so that will be used."))
996 == PED_EXCEPTION_CANCEL)
1005 if (!_parse_header (disk, gpt, &write_back))
1006 goto error_free_gpt;
1009 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
1011 goto error_free_gpt;
1013 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
1014 if (ptes_crc != PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32))
1017 (PED_EXCEPTION_ERROR,
1018 PED_EXCEPTION_CANCEL,
1019 _("primary partition table array CRC mismatch"));
1020 goto error_free_ptes;
1023 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
1024 for (i = 0; i < gpt_disk_data->entry_count; i++)
1026 GuidPartitionEntry_t *pte
1027 = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
1030 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
1033 part = _parse_part_entry (disk, pte);
1035 goto error_delete_all;
1037 part->fs_type = ped_file_system_probe (&part->geom);
1040 PedConstraint *constraint_exact = ped_constraint_exact (&part->geom);
1041 if (!ped_disk_add_partition (disk, part, constraint_exact))
1043 ped_constraint_destroy (constraint_exact);
1044 ped_partition_destroy (part);
1045 goto error_delete_all;
1047 ped_constraint_destroy (constraint_exact);
1051 #ifndef DISCOVER_ONLY
1053 ped_disk_commit_to_dev (disk);
1060 ped_disk_delete_all (disk);
1064 pth_free (primary_gpt);
1065 pth_free (backup_gpt);
1071 #ifndef DISCOVER_ONLY
1072 /* Write the protective MBR (to keep DOS happy) */
1074 _write_pmbr (PedDevice *dev)
1076 /* The UEFI spec is not clear about what to do with the following
1077 elements of the Protective MBR (pmbr): BootCode (0-440B),
1078 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1079 With this in mind, we try not to modify these elements. */
1081 if (!ptt_read_sector (dev, 0, &s0))
1083 LegacyMBR_t *pmbr = s0;
1085 /* Zero out the legacy partitions. */
1086 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1088 pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1089 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1090 pmbr->PartitionRecord[0].StartSector = 1;
1091 pmbr->PartitionRecord[0].EndHead = 0xFE;
1092 pmbr->PartitionRecord[0].EndSector = 0xFF;
1093 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1094 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1095 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1096 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1098 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1100 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1107 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1108 GuidPartitionTableHeader_t **gpt_p)
1110 GPTDiskData *gpt_disk_data = disk->disk_specific;
1111 GuidPartitionTableHeader_t *gpt;
1113 *gpt_p = pth_new_zeroed (disk->dev);
1117 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1118 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1121 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1122 gpt->HeaderCRC32 = 0;
1127 PedSector ptes_size = gpt_disk_data->entry_count
1128 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1130 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1131 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1132 gpt->PartitionEntryLBA
1133 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1137 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1138 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1139 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1142 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1143 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1144 gpt->DiskGUID = gpt_disk_data->uuid;
1145 gpt->NumberOfPartitionEntries
1146 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1147 gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1148 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1151 if (pth_crc32 (disk->dev, gpt, &crc) != 0)
1154 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
1159 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1161 GPTPartitionData *gpt_part_data = part->disk_specific;
1164 PED_ASSERT (gpt_part_data != NULL, return);
1166 pte->PartitionTypeGuid = gpt_part_data->type;
1167 pte->UniquePartitionGuid = gpt_part_data->uuid;
1168 pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1169 pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1170 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1172 if (gpt_part_data->hidden)
1173 pte->Attributes.RequiredToFunction = 1;
1175 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1176 pte->PartitionName[i]
1177 = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1181 gpt_write (const PedDisk *disk)
1183 GPTDiskData *gpt_disk_data;
1184 GuidPartitionEntry_t *ptes;
1187 GuidPartitionTableHeader_t *gpt;
1191 PED_ASSERT (disk != NULL, goto error);
1192 PED_ASSERT (disk->dev != NULL, goto error);
1193 PED_ASSERT (disk->disk_specific != NULL, goto error);
1195 gpt_disk_data = disk->disk_specific;
1197 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1198 ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1201 memset (ptes, 0, ptes_size);
1202 for (part = ped_disk_next_partition (disk, NULL); part;
1203 part = ped_disk_next_partition (disk, part))
1205 if (part->type != 0)
1207 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1210 ptes_crc = efi_crc32 (ptes, ptes_size);
1212 /* Write protective MBR */
1213 if (!_write_pmbr (disk->dev))
1214 goto error_free_ptes;
1216 /* Write PTH and PTEs */
1217 /* FIXME: Caution: this code is nearly identical to what's just below. */
1218 if (_generate_header (disk, 0, ptes_crc, &gpt) != 0)
1219 goto error_free_ptes;
1220 pth_raw = pth_get_raw (disk->dev, gpt);
1222 if (pth_raw == NULL)
1223 goto error_free_ptes;
1224 int write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1227 goto error_free_ptes;
1228 if (!ped_device_write (disk->dev, ptes, 2,
1229 ptes_size / disk->dev->sector_size))
1230 goto error_free_ptes;
1232 /* Write Alternate PTH & PTEs */
1233 /* FIXME: Caution: this code is nearly identical to what's just above. */
1234 if (_generate_header (disk, 1, ptes_crc, &gpt) != 0)
1235 goto error_free_ptes;
1236 pth_raw = pth_get_raw (disk->dev, gpt);
1238 if (pth_raw == NULL)
1239 goto error_free_ptes;
1240 write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1243 goto error_free_ptes;
1244 if (!ped_device_write (disk->dev, ptes,
1245 disk->dev->length - 1 -
1246 ptes_size / disk->dev->sector_size,
1247 ptes_size / disk->dev->sector_size))
1248 goto error_free_ptes;
1251 return ped_device_sync (disk->dev);
1258 #endif /* !DISCOVER_ONLY */
1261 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1264 PedConstraint *constraint_exact;
1265 PED_ASSERT (disk != NULL, return 0);
1267 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1268 start, start + length - 1);
1272 constraint_exact = ped_constraint_exact (&part->geom);
1273 if (!ped_disk_add_partition (disk, part, constraint_exact))
1274 goto error_destroy_constraint;
1275 ped_constraint_destroy (constraint_exact);
1278 error_destroy_constraint:
1279 ped_constraint_destroy (constraint_exact);
1280 ped_partition_destroy (part);
1285 static PedPartition *
1286 gpt_partition_new (const PedDisk *disk,
1287 PedPartitionType part_type,
1288 const PedFileSystemType *fs_type, PedSector start,
1292 GPTPartitionData *gpt_part_data;
1294 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1301 gpt_part_data = part->disk_specific =
1302 ped_malloc (sizeof (GPTPartitionData));
1304 goto error_free_part;
1306 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1307 gpt_part_data->lvm = 0;
1308 gpt_part_data->raid = 0;
1309 gpt_part_data->boot = 0;
1310 gpt_part_data->bios_grub = 0;
1311 gpt_part_data->hp_service = 0;
1312 gpt_part_data->hidden = 0;
1313 gpt_part_data->msftres = 0;
1314 gpt_part_data->atvrecv = 0;
1315 uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1316 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1317 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1321 _ped_partition_free (part);
1326 static PedPartition *
1327 gpt_partition_duplicate (const PedPartition *part)
1329 PedPartition *result;
1330 GPTPartitionData *part_data = part->disk_specific;
1331 GPTPartitionData *result_data;
1333 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1334 part->geom.start, part->geom.end);
1337 result->num = part->num;
1339 if (result->type != 0)
1342 result_data = result->disk_specific =
1343 ped_malloc (sizeof (GPTPartitionData));
1345 goto error_free_part;
1347 result_data->type = part_data->type;
1348 result_data->uuid = part_data->uuid;
1349 strcpy (result_data->name, part_data->name);
1353 _ped_partition_free (result);
1359 gpt_partition_destroy (PedPartition *part)
1361 if (part->type == 0)
1363 PED_ASSERT (part->disk_specific != NULL, return);
1364 free (part->disk_specific);
1367 _ped_partition_free (part);
1371 gpt_partition_set_system (PedPartition *part,
1372 const PedFileSystemType *fs_type)
1374 GPTPartitionData *gpt_part_data = part->disk_specific;
1376 PED_ASSERT (gpt_part_data != NULL, return 0);
1378 part->fs_type = fs_type;
1380 if (gpt_part_data->lvm)
1382 gpt_part_data->type = PARTITION_LVM_GUID;
1385 if (gpt_part_data->raid)
1387 gpt_part_data->type = PARTITION_RAID_GUID;
1390 if (gpt_part_data->boot)
1392 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1395 if (gpt_part_data->bios_grub)
1397 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1400 if (gpt_part_data->hp_service)
1402 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1405 if (gpt_part_data->msftres)
1407 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1410 if (gpt_part_data->atvrecv)
1412 gpt_part_data->type = PARTITION_APPLE_TV_RECOVERY_GUID;
1418 if (strncmp (fs_type->name, "fat", 3) == 0
1419 || strcmp (fs_type->name, "ntfs") == 0)
1421 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1424 if (strncmp (fs_type->name, "hfs", 3) == 0)
1426 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1429 if (strstr (fs_type->name, "swap"))
1431 gpt_part_data->type = PARTITION_SWAP_GUID;
1436 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1440 /* Allocate metadata partitions for the GPTH and PTES */
1442 gpt_alloc_metadata (PedDisk *disk)
1444 PedSector gptlength, pteslength = 0;
1445 GPTDiskData *gpt_disk_data;
1447 PED_ASSERT (disk != NULL, return 0);
1448 PED_ASSERT (disk->dev != NULL, return 0);
1449 PED_ASSERT (disk->disk_specific != NULL, return 0);
1450 gpt_disk_data = disk->disk_specific;
1452 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1453 disk->dev->sector_size);
1454 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1455 * sizeof (GuidPartitionEntry_t),
1456 disk->dev->sector_size);
1458 /* metadata at the start of the disk includes the MBR */
1459 if (!add_metadata_part (disk, GPT_PMBR_LBA,
1460 GPT_PMBR_SECTORS + gptlength + pteslength))
1463 /* metadata at the end of the disk */
1464 if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1465 gptlength + pteslength))
1471 /* Does nothing, as the read/new/destroy functions maintain part->num */
1473 gpt_partition_enumerate (PedPartition *part)
1475 GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1478 /* never change the partition numbers */
1479 if (part->num != -1)
1482 for (i = 1; i <= gpt_disk_data->entry_count; i++)
1484 if (!ped_disk_get_partition (part->disk, i))
1491 PED_ASSERT (0, return 0);
1493 return 0; /* used if debug is disabled */
1497 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1499 GPTPartitionData *gpt_part_data;
1500 PED_ASSERT (part != NULL, return 0);
1501 PED_ASSERT (part->disk_specific != NULL, return 0);
1502 gpt_part_data = part->disk_specific;
1506 case PED_PARTITION_BOOT:
1507 gpt_part_data->boot = state;
1510 = gpt_part_data->lvm
1511 = gpt_part_data->bios_grub
1512 = gpt_part_data->hp_service
1513 = gpt_part_data->msftres
1514 = gpt_part_data->atvrecv = 0;
1515 return gpt_partition_set_system (part, part->fs_type);
1516 case PED_PARTITION_BIOS_GRUB:
1517 gpt_part_data->bios_grub = state;
1520 = gpt_part_data->lvm
1521 = gpt_part_data->boot
1522 = gpt_part_data->hp_service
1523 = gpt_part_data->msftres
1524 = gpt_part_data->atvrecv = 0;
1525 return gpt_partition_set_system (part, part->fs_type);
1526 case PED_PARTITION_RAID:
1527 gpt_part_data->raid = state;
1530 = gpt_part_data->lvm
1531 = gpt_part_data->bios_grub
1532 = gpt_part_data->hp_service
1533 = gpt_part_data->msftres
1534 = gpt_part_data->atvrecv = 0;
1535 return gpt_partition_set_system (part, part->fs_type);
1536 case PED_PARTITION_LVM:
1537 gpt_part_data->lvm = state;
1540 = gpt_part_data->raid
1541 = gpt_part_data->bios_grub
1542 = gpt_part_data->hp_service
1543 = gpt_part_data->msftres
1544 = gpt_part_data->atvrecv = 0;
1545 return gpt_partition_set_system (part, part->fs_type);
1546 case PED_PARTITION_HPSERVICE:
1547 gpt_part_data->hp_service = state;
1550 = gpt_part_data->raid
1551 = gpt_part_data->lvm
1552 = gpt_part_data->bios_grub
1553 = gpt_part_data->msftres
1554 = gpt_part_data->atvrecv = 0;
1555 return gpt_partition_set_system (part, part->fs_type);
1556 case PED_PARTITION_MSFT_RESERVED:
1557 gpt_part_data->msftres = state;
1560 = gpt_part_data->raid
1561 = gpt_part_data->lvm
1562 = gpt_part_data->bios_grub
1563 = gpt_part_data->hp_service
1564 = gpt_part_data->atvrecv = 0;
1565 return gpt_partition_set_system (part, part->fs_type);
1566 case PED_PARTITION_APPLE_TV_RECOVERY:
1567 gpt_part_data->atvrecv = state;
1570 = gpt_part_data->raid
1571 = gpt_part_data->lvm
1572 = gpt_part_data->bios_grub
1573 = gpt_part_data->hp_service
1574 = gpt_part_data->msftres = 0;
1575 return gpt_partition_set_system (part, part->fs_type);
1576 case PED_PARTITION_HIDDEN:
1577 gpt_part_data->hidden = state;
1579 case PED_PARTITION_SWAP:
1580 case PED_PARTITION_ROOT:
1581 case PED_PARTITION_LBA:
1589 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1591 GPTPartitionData *gpt_part_data;
1592 PED_ASSERT (part->disk_specific != NULL, return 0);
1593 gpt_part_data = part->disk_specific;
1597 case PED_PARTITION_RAID:
1598 return gpt_part_data->raid;
1599 case PED_PARTITION_LVM:
1600 return gpt_part_data->lvm;
1601 case PED_PARTITION_BOOT:
1602 return gpt_part_data->boot;
1603 case PED_PARTITION_BIOS_GRUB:
1604 return gpt_part_data->bios_grub;
1605 case PED_PARTITION_HPSERVICE:
1606 return gpt_part_data->hp_service;
1607 case PED_PARTITION_MSFT_RESERVED:
1608 return gpt_part_data->msftres;
1609 case PED_PARTITION_APPLE_TV_RECOVERY:
1610 return gpt_part_data->atvrecv;
1611 case PED_PARTITION_HIDDEN:
1612 return gpt_part_data->hidden;
1613 case PED_PARTITION_SWAP:
1614 case PED_PARTITION_LBA:
1615 case PED_PARTITION_ROOT:
1623 gpt_partition_is_flag_available (const PedPartition *part,
1624 PedPartitionFlag flag)
1628 case PED_PARTITION_RAID:
1629 case PED_PARTITION_LVM:
1630 case PED_PARTITION_BOOT:
1631 case PED_PARTITION_BIOS_GRUB:
1632 case PED_PARTITION_HPSERVICE:
1633 case PED_PARTITION_MSFT_RESERVED:
1634 case PED_PARTITION_APPLE_TV_RECOVERY:
1635 case PED_PARTITION_HIDDEN:
1637 case PED_PARTITION_SWAP:
1638 case PED_PARTITION_ROOT:
1639 case PED_PARTITION_LBA:
1647 gpt_partition_set_name (PedPartition *part, const char *name)
1649 GPTPartitionData *gpt_part_data = part->disk_specific;
1651 strncpy (gpt_part_data->name, name, 36);
1652 gpt_part_data->name[36] = 0;
1656 gpt_partition_get_name (const PedPartition *part)
1658 GPTPartitionData *gpt_part_data = part->disk_specific;
1659 return gpt_part_data->name;
1663 gpt_get_max_primary_partition_count (const PedDisk *disk)
1665 const GPTDiskData *gpt_disk_data = disk->disk_specific;
1666 return gpt_disk_data->entry_count;
1670 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1671 * According to the specs the first LBA (LBA0) is not relevant (it exists
1672 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1673 * header. The header is as big as the block size. After the header we
1674 * find the Entry array. Each element of said array, describes each
1675 * partition. One can have as much elements as can fit between the end of
1676 * the second LBA (where the header ends) and the FirstUsableLBA.
1677 * FirstUsableLBA is the first logical block that is used for contents
1678 * and is defined in header.
1680 * /---------------------------------------------------\
1681 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1683 * \---------------------------------------------------/
1685 * /----------/ \----------\
1686 * /-----------------------------------------\
1687 * | E1 | E2 | E3 |...............| EN |
1688 * \-----------------------------------------/
1690 * The number of possible partitions or supported partitions is:
1691 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1692 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1695 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1697 GuidPartitionTableHeader_t *pth = NULL;
1698 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1700 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1701 || ped_device_read (disk->dev, pth_raw,
1702 disk->dev->length, GPT_HEADER_SECTORS))
1703 pth = pth_new_from_raw (disk->dev, pth_raw);
1709 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1710 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1715 static PedConstraint *
1716 _non_metadata_constraint (const PedDisk *disk)
1718 GPTDiskData *gpt_disk_data = disk->disk_specific;
1720 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1724 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1726 PED_ASSERT (part != NULL, return 0);
1728 if (_ped_partition_attempt_align (part, constraint,
1729 _non_metadata_constraint (part->disk)))
1732 #ifndef DISCOVER_ONLY
1733 ped_exception_throw (PED_EXCEPTION_ERROR,
1734 PED_EXCEPTION_CANCEL,
1735 _("Unable to satisfy all constraints on the partition."));
1740 #include "pt-common.h"
1741 PT_define_limit_functions (gpt)
1743 static PedDiskOps gpt_disk_ops =
1745 clobber: NULL_IF_DISCOVER_ONLY (gpt_clobber),
1746 write: NULL_IF_DISCOVER_ONLY (gpt_write),
1748 partition_set_name: gpt_partition_set_name,
1749 partition_get_name: gpt_partition_get_name,
1751 PT_op_function_initializers (gpt)
1754 static PedDiskType gpt_disk_type =
1759 features: PED_DISK_TYPE_PARTITION_NAME
1763 ped_disk_gpt_init ()
1765 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1766 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1768 ped_disk_type_register (&gpt_disk_type);
1772 ped_disk_gpt_done ()
1774 ped_disk_type_unregister (&gpt_disk_type);