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-2009 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 }})
135 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
140 uint32_t HeaderCRC32;
143 uint64_t AlternateLBA;
144 uint64_t FirstUsableLBA;
145 uint64_t LastUsableLBA;
147 uint64_t PartitionEntryLBA;
148 uint32_t NumberOfPartitionEntries;
149 uint32_t SizeOfPartitionEntry;
150 uint32_t PartitionEntryArrayCRC32;
154 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
156 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
157 uint64_t RequiredToFunction:1;
158 uint64_t Reserved:47;
159 uint64_t GuidSpecific:16;
161 # warning "Using crippled partition entry type"
162 uint32_t RequiredToFunction:1;
163 uint32_t Reserved:32;
165 uint32_t GuidSpecific:16;
169 struct __attribute__ ((packed)) _GuidPartitionEntry_t
171 efi_guid_t PartitionTypeGuid;
172 efi_guid_t UniquePartitionGuid;
173 uint64_t StartingLBA;
175 GuidPartitionEntryAttributes_t Attributes;
176 efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
179 #define GPT_PMBR_LBA 0
180 #define GPT_PMBR_SECTORS 1
181 #define GPT_PRIMARY_HEADER_LBA 1
182 #define GPT_HEADER_SECTORS 1
183 #define GPT_PRIMARY_PART_TABLE_LBA 2
186 These values are only defaults. The actual on-disk structures
187 may define different sizes, so use those unless creating a new GPT disk!
190 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
192 /* Number of actual partition entries should be calculated as: */
193 #define GPT_DEFAULT_PARTITION_ENTRIES \
194 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
195 sizeof(GuidPartitionEntry_t))
197 struct __attribute__ ((packed)) _PartitionRecord_t
199 /* Not used by EFI firmware. Set to 0x80 to indicate that this
200 is the bootable legacy partition. */
201 uint8_t BootIndicator;
203 /* Start of partition in CHS address, not used by EFI firmware. */
206 /* Start of partition in CHS address, not used by EFI firmware. */
209 /* Start of partition in CHS address, not used by EFI firmware. */
212 /* OS type. A value of 0xEF defines an EFI system partition.
213 Other values are reserved for legacy operating systems, and
214 allocated independently of the EFI specification. */
217 /* End of partition in CHS address, not used by EFI firmware. */
220 /* End of partition in CHS address, not used by EFI firmware. */
223 /* End of partition in CHS address, not used by EFI firmware. */
226 /* Starting LBA address of the partition on the disk. Used by
227 EFI firmware to define the start of the partition. */
228 uint32_t StartingLBA;
230 /* Size of partition in LBA. Used by EFI firmware to determine
231 the size of the partition. */
235 /* Protected Master Boot Record & Legacy MBR share same structure */
236 /* Needs to be packed because the u16s force misalignment. */
237 struct __attribute__ ((packed)) _LegacyMBR_t
239 uint8_t BootCode[440];
240 uint32_t UniqueMBRSignature;
242 PartitionRecord_t PartitionRecord[4];
246 /* uses libparted's disk_specific field in PedDisk, to store our info */
247 struct __attribute__ ((packed)) _GPTDiskData
249 PedGeometry data_area;
254 /* uses libparted's disk_specific field in PedPartition, to store our info */
255 typedef struct _GPTPartitionData
269 static PedDiskType gpt_disk_type;
271 static inline uint32_t
272 pth_get_size (const PedDevice *dev)
274 return GPT_HEADER_SECTORS * dev->sector_size;
277 static inline uint32_t
278 pth_get_size_static (const PedDevice *dev)
280 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
283 static inline uint32_t
284 pth_get_size_rsv2 (const PedDevice *dev)
286 return pth_get_size (dev) - pth_get_size_static (dev);
289 static GuidPartitionTableHeader_t *
290 pth_new (const PedDevice *dev)
292 GuidPartitionTableHeader_t *pth =
293 ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
295 pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
300 static GuidPartitionTableHeader_t *
301 pth_new_zeroed (const PedDevice *dev)
303 GuidPartitionTableHeader_t *pth = pth_new (dev);
305 memset (pth, 0, pth_get_size_static (dev));
306 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
311 static GuidPartitionTableHeader_t *
312 pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
314 GuidPartitionTableHeader_t *pth = pth_new (dev);
316 PED_ASSERT (pth_raw != NULL, return 0);
318 memcpy (pth, pth_raw, pth_get_size_static (dev));
319 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
320 pth_get_size_rsv2 (dev));
326 pth_free (GuidPartitionTableHeader_t *pth)
330 PED_ASSERT (pth->Reserved2 != NULL, return);
332 free (pth->Reserved2);
337 pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
339 PED_ASSERT (pth != NULL, return 0);
340 PED_ASSERT (pth->Reserved2 != NULL, return 0);
342 int size_static = pth_get_size_static (dev);
343 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
347 memcpy (pth_raw, pth, size_static);
348 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
354 * swap_uuid_and_efi_guid() - converts between uuid formats
355 * @uuid - uuid_t in either format (converts it to the other)
357 * There are two different representations for Globally Unique Identifiers
360 * The RFC specifies a UUID as a string of 16 bytes, essentially
361 * a big-endian array of char.
362 * Intel, in their EFI Specification, references the same RFC, but
363 * then defines a GUID as a structure of little-endian fields.
364 * Coincidentally, both structures have the same format when unparsed.
366 * When read from disk, EFI GUIDs are in struct of little endian format,
367 * and need to be converted to be treated as uuid_t in memory.
369 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
374 swap_uuid_and_efi_guid (uuid_t uuid)
376 efi_guid_t *guid = (efi_guid_t *) uuid;
378 PED_ASSERT (uuid != NULL, return);
379 guid->time_low = PED_SWAP32 (guid->time_low);
380 guid->time_mid = PED_SWAP16 (guid->time_mid);
381 guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
384 /* returns the EFI-style CRC32 value for buf
385 * This function uses the crc32 function by Gary S. Brown,
386 * but seeds the function with ~0, and xor's with ~0 at the end.
388 static inline uint32_t
389 efi_crc32 (const void *buf, unsigned long len)
391 return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
394 /* Compute the crc32 checksum of the partition table header
395 and store it in *CRC32. Return 0 upon success. Return 1
396 upon failure to allocate space. */
398 pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth,
401 PED_ASSERT (dev != NULL, return 0);
402 PED_ASSERT (pth != NULL, return 0);
404 uint8_t *pth_raw = pth_get_raw (dev, pth);
408 *crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
415 guid_cmp (efi_guid_t left, efi_guid_t right)
417 return memcmp (&left, &right, sizeof (efi_guid_t));
420 /* checks if 'mbr' is a protective MBR partition table */
422 _pmbr_is_valid (const LegacyMBR_t *mbr)
426 PED_ASSERT (mbr != NULL, return 0);
428 if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
430 for (i = 0; i < 4; i++)
432 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
439 gpt_probe (const PedDevice *dev)
441 GuidPartitionTableHeader_t *gpt = NULL;
442 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
443 int gpt_sig_found = 0;
445 PED_ASSERT (dev != NULL, return 0);
447 if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
448 || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
450 gpt = pth_new_from_raw (dev, pth_raw);
451 if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
463 if (!ptt_read_sector (dev, 0, &label))
467 if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
469 int ex_status = ped_exception_throw
470 (PED_EXCEPTION_WARNING,
471 PED_EXCEPTION_YES_NO,
472 _("%s contains GPT signatures, indicating that it has "
473 "a GPT table. However, it does not have a valid "
474 "fake msdos partition table, as it should. Perhaps "
475 "it was corrupted -- possibly by a program that "
476 "doesn't understand GPT partition tables. Or "
477 "perhaps you deleted the GPT table, and are now "
478 "using an msdos partition table. Is this a GPT "
481 if (ex_status == PED_EXCEPTION_NO)
489 #ifndef DISCOVER_ONLY
490 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
492 gpt_clobber (PedDevice *dev)
494 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
495 GuidPartitionTableHeader_t *gpt;
497 PED_ASSERT (dev != NULL, return 0);
500 * TO DISCUSS: check whether checksum is correct?
501 * If not, we might get a wrong AlternateLBA field and destroy
502 * one sector of random data.
504 if (!ped_device_read (dev, pth_raw,
505 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
511 gpt = pth_new_from_raw (dev, pth_raw);
514 if (!ptt_clear_sectors (dev, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
515 goto error_free_with_gpt;
516 if (!ptt_clear_sectors (dev, GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
517 goto error_free_with_gpt;
518 if (!ptt_clear_sectors (dev, dev->length - GPT_HEADER_SECTORS,
520 goto error_free_with_gpt;
522 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1)
524 if (!ped_device_write (dev, gpt,
525 PED_LE64_TO_CPU (gpt->AlternateLBA),
538 #endif /* !DISCOVER_ONLY */
541 gpt_alloc (const PedDevice *dev)
544 GPTDiskData *gpt_disk_data;
545 PedSector data_start, data_end;
547 disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
550 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
551 if (!disk->disk_specific)
552 goto error_free_disk;
554 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
555 data_end = dev->length - 2
556 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
557 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
558 data_end - data_start + 1);
559 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
560 uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
561 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
571 gpt_duplicate (const PedDisk *disk)
574 GPTDiskData *new_disk_data;
575 GPTDiskData *old_disk_data;
577 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
581 old_disk_data = disk->disk_specific;
582 new_disk_data = new_disk->disk_specific;
584 ped_geometry_init (&new_disk_data->data_area, disk->dev,
585 old_disk_data->data_area.start,
586 old_disk_data->data_area.length);
587 new_disk_data->entry_count = old_disk_data->entry_count;
588 new_disk_data->uuid = old_disk_data->uuid;
593 gpt_free (PedDisk *disk)
595 ped_disk_delete_all (disk);
596 free (disk->disk_specific);
597 _ped_disk_free (disk);
600 /* Given GUID Partition table header, GPT, read its partition array
601 entries from DISK into malloc'd storage. Set *PTES_BYTES to the
602 number of bytes required. Upon success, return a pointer to the
603 resulting buffer. Otherwise, set errno and return NULL. */
605 gpt_read_PE_array (PedDisk const *disk, GuidPartitionTableHeader_t const *gpt,
608 GPTDiskData *gpt_disk_data = disk->disk_specific;
609 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
610 *ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
611 size_t ptes_sectors = ped_div_round_up (*ptes_bytes,
612 disk->dev->sector_size);
614 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
619 void *ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
623 if (!ped_device_read (disk->dev, ptes,
624 PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
626 int saved_errno = errno;
636 check_PE_array_CRC (PedDisk const *disk,
637 GuidPartitionTableHeader_t const *gpt, bool *valid)
640 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
644 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
645 *valid = (ptes_crc == gpt->PartitionEntryArrayCRC32);
651 _header_is_valid (PedDisk const *disk, GuidPartitionTableHeader_t *gpt,
654 uint32_t crc, origcrc;
655 PedDevice const *dev = disk->dev;
657 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
660 * "While the GUID Partition Table Header's size may increase
661 * in the future it cannot span more than one block on the
662 * device." EFI Specification, version 1.10, 11.2.2.1
664 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
665 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
668 /* The SizeOfPartitionEntry must be a multiple of 8 and
669 no smaller than the size of the PartitionEntry structure.
670 We also require that be no larger than 1/16th of UINT32_MAX,
671 as an additional sanity check. */
672 uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
674 || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
677 if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
680 PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
681 /* The backup table's AlternateLBA must be 1. */
682 if (my_lba != 1 && alt_lba != 1)
685 /* The alt_lba must never be the same as my_lba. */
686 if (alt_lba == my_lba)
690 if (check_PE_array_CRC (disk, gpt, &crc_match) != 0 || !crc_match)
693 origcrc = gpt->HeaderCRC32;
694 gpt->HeaderCRC32 = 0;
695 if (pth_crc32 (dev, gpt, &crc) != 0)
697 gpt->HeaderCRC32 = origcrc;
699 return crc == PED_LE32_TO_CPU (origcrc);
703 _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
706 GPTDiskData *gpt_disk_data = disk->disk_specific;
707 PedSector first_usable;
708 PedSector last_usable;
709 PedSector last_usable_if_grown, last_usable_min_default;
710 static int asked_already;
712 #ifndef DISCOVER_ONLY
713 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
715 if (ped_exception_throw
716 (PED_EXCEPTION_WARNING,
717 PED_EXCEPTION_IGNORE_CANCEL,
718 _("The format of the GPT partition table is version "
719 "%x, which is newer than what Parted can "
720 "recognise. Please tell us! bug-parted@gnu.org"),
721 PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
726 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
727 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
729 /* Need to check whether the volume has grown, the LastUsableLBA is
730 normally set to disk->dev->length - 2 - ptes_size (at least for parted
731 created volumes), where ptes_size is the number of entries *
732 size of each entry / sector size or 16k / sector size, whatever the greater.
733 If the volume has grown, offer the user the chance to use the new
734 space or continue with the current usable area. Only ask once per
735 parted invocation. */
738 = (disk->dev->length - 2 -
739 ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
740 (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
741 disk->dev->sector_size));
743 last_usable_min_default = disk->dev->length - 2 -
744 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
746 if (last_usable_if_grown > last_usable_min_default)
748 last_usable_if_grown = last_usable_min_default;
751 PED_ASSERT (last_usable > first_usable, return 0);
752 PED_ASSERT (last_usable <= disk->dev->length, return 0);
754 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
755 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
757 if (!asked_already && last_usable < last_usable_if_grown)
760 PedExceptionOption q;
762 q = ped_exception_throw
763 (PED_EXCEPTION_WARNING,
764 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
765 _("Not all of the space available to %s appears "
766 "to be used, you can fix the GPT to use all of the "
767 "space (an extra %llu blocks) or continue with the "
768 "current setting? "), disk->dev->path,
769 (uint64_t) (last_usable_if_grown - last_usable));
771 if (q == PED_EXCEPTION_FIX)
773 last_usable = last_usable_if_grown;
776 else if (q != PED_EXCEPTION_UNHANDLED)
782 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
783 first_usable, last_usable - first_usable + 1);
785 gpt_disk_data->entry_count
786 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
787 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
788 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
790 gpt_disk_data->uuid = gpt->DiskGUID;
795 static PedPartition *
796 _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
799 GPTPartitionData *gpt_part_data;
802 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
803 PED_LE64_TO_CPU (pte->StartingLBA),
804 PED_LE64_TO_CPU (pte->EndingLBA));
808 gpt_part_data = part->disk_specific;
809 gpt_part_data->type = pte->PartitionTypeGuid;
810 gpt_part_data->uuid = pte->UniquePartitionGuid;
811 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
812 gpt_part_data->name[i] =
813 (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
814 gpt_part_data->name[i] = 0;
816 gpt_part_data->lvm = gpt_part_data->raid
817 = gpt_part_data->boot = gpt_part_data->hp_service
818 = gpt_part_data->hidden = gpt_part_data->msftres
819 = gpt_part_data->bios_grub = 0;
821 if (pte->Attributes.RequiredToFunction & 0x1)
822 gpt_part_data->hidden = 1;
824 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
825 gpt_part_data->boot = 1;
826 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
827 gpt_part_data->bios_grub = 1;
828 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
829 gpt_part_data->raid = 1;
830 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
831 gpt_part_data->lvm = 1;
832 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
833 gpt_part_data->hp_service = 1;
834 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
835 gpt_part_data->msftres = 1;
840 /* Read the primary GPT at sector 1 of DEV.
841 Verify its CRC and that of its partition entry array.
842 If they are valid, read the backup GPT specified by AlternateLBA.
843 If not, read the backup GPT in the last sector of the disk.
844 Return 1 if any read fails.
845 Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
846 Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
847 If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
848 number in which it was found. */
850 gpt_read_headers (PedDisk const *disk,
851 GuidPartitionTableHeader_t **primary_gpt,
852 GuidPartitionTableHeader_t **backup_gpt,
853 PedSector *backup_sector_num_p)
857 PedDevice const *dev = disk->dev;
860 if (!ptt_read_sector (dev, 1, &s1))
863 GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
867 GuidPartitionTableHeader_t *pri = t;
869 bool valid_primary = _header_is_valid (disk, pri, 1);
875 PedSector backup_sector_num =
877 ? PED_LE64_TO_CPU (pri->AlternateLBA)
881 if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
883 t = pth_new_from_raw (dev, s_bak);
888 GuidPartitionTableHeader_t *bak = t;
889 if (_header_is_valid (disk, bak, backup_sector_num))
892 *backup_sector_num_p = backup_sector_num;
900 /************************************************************
901 * Intel is changing the EFI Spec. (after v1.02) to say that a
902 * disk is considered to have a GPT label only if the GPT
903 * structures are correct, and the MBR is actually a Protective
904 * MBR (has one 0xEE type partition).
905 * Problem occurs when a GPT-partitioned disk is then
906 * edited with a legacy (non-GPT-aware) application, such as
907 * fdisk (which doesn't generally erase the PGPT or AGPT).
908 * How should such a disk get handled? As a GPT disk (throwing
909 * away the fdisk changes), or as an MSDOS disk (throwing away
910 * the GPT information). Previously, I've taken the GPT-is-right,
911 * MBR is wrong, approach, to stay consistent with the EFI Spec.
912 * Intel disagrees, saying the disk should then be treated
913 * as having a msdos label, not a GPT label. If this is true,
914 * then what's the point of having an AGPT, since if the PGPT
915 * is screwed up, likely the PMBR is too, and the PMBR becomes
916 * a single point of failure.
917 * So, in the Linux kernel, I'm going to test for PMBR, and
918 * warn if it's not there, and treat the disk as MSDOS, with a note
919 * for users to use Parted to "fix up" their disk if they
920 * really want it to be considered GPT.
921 ************************************************************/
923 gpt_read (PedDisk *disk)
925 GPTDiskData *gpt_disk_data = disk->disk_specific;
927 #ifndef DISCOVER_ONLY
931 ped_disk_delete_all (disk);
933 /* motivation: let the user decide about the pmbr... during
934 ped_disk_probe(), they probably didn't get a choice... */
935 if (!gpt_probe (disk->dev))
938 GuidPartitionTableHeader_t *gpt = NULL;
939 GuidPartitionTableHeader_t *primary_gpt;
940 GuidPartitionTableHeader_t *backup_gpt;
941 PedSector backup_sector_num;
942 int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
946 /* This includes the case in which there used to be a GPT partition
947 table here, with an alternate LBA that extended beyond the current
948 end-of-device. It's treated as a non-match. */
950 /* Another possibility:
951 The primary header is ok, but backup is corrupt.
952 In the UEFI spec, this means the primary GUID table
953 is officially invalid. */
954 pth_free (backup_gpt);
955 pth_free (primary_gpt);
959 if (primary_gpt && backup_gpt)
961 /* Both are valid. */
962 if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
964 #ifndef DISCOVER_ONLY
965 switch (ped_exception_throw
966 (PED_EXCEPTION_ERROR,
967 (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
968 | PED_EXCEPTION_IGNORE),
969 _("The backup GPT table is not at the end of the disk, as it "
970 "should be. This might mean that another operating system "
971 "believes the disk is smaller. Fix, by moving the backup "
972 "to the end (and removing the old backup)?")))
974 case PED_EXCEPTION_CANCEL:
976 case PED_EXCEPTION_FIX:
977 ptt_clear_sectors (disk->dev,
978 PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
984 #endif /* !DISCOVER_ONLY */
987 pth_free (backup_gpt);
989 else if (!primary_gpt && !backup_gpt)
991 /* Both are corrupt. */
992 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
993 _("Both the primary and backup GPT tables "
994 "are corrupt. Try making a fresh table, "
995 "and using Parted's rescue feature to "
996 "recover partitions."));
999 else if (primary_gpt && !backup_gpt)
1001 /* The primary header is ok, but backup is corrupt. */
1002 if (ped_exception_throw
1003 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
1004 _("The backup GPT table is corrupt, but the "
1005 "primary appears OK, so that will be used."))
1006 == PED_EXCEPTION_CANCEL)
1007 goto error_free_gpt;
1011 else /* !primary_gpt && backup_gpt */
1013 /* primary GPT corrupt, backup is ok. */
1014 if (ped_exception_throw
1015 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
1016 _("The primary GPT table is corrupt, but the "
1017 "backup appears OK, so that will be used."))
1018 == PED_EXCEPTION_CANCEL)
1019 goto error_free_gpt;
1026 if (!_parse_header (disk, gpt, &write_back))
1027 goto error_free_gpt;
1030 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
1032 goto error_free_gpt;
1034 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
1035 if (ptes_crc != gpt->PartitionEntryArrayCRC32)
1038 (PED_EXCEPTION_ERROR,
1039 PED_EXCEPTION_CANCEL,
1040 _("primary partition table array CRC mismatch"));
1041 goto error_free_ptes;
1044 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
1045 for (i = 0; i < gpt_disk_data->entry_count; i++)
1047 GuidPartitionEntry_t *pte
1048 = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
1050 PedConstraint *constraint_exact;
1052 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
1055 part = _parse_part_entry (disk, pte);
1057 goto error_delete_all;
1059 part->fs_type = ped_file_system_probe (&part->geom);
1062 constraint_exact = ped_constraint_exact (&part->geom);
1063 if (!ped_disk_add_partition (disk, part, constraint_exact))
1065 ped_partition_destroy (part);
1066 goto error_delete_all;
1068 ped_constraint_destroy (constraint_exact);
1072 #ifndef DISCOVER_ONLY
1074 ped_disk_commit_to_dev (disk);
1081 ped_disk_delete_all (disk);
1085 pth_free (primary_gpt);
1086 pth_free (backup_gpt);
1092 #ifndef DISCOVER_ONLY
1093 /* Write the protective MBR (to keep DOS happy) */
1095 _write_pmbr (PedDevice *dev)
1097 /* The UEFI spec is not clear about what to do with the following
1098 elements of the Protective MBR (pmbr): BootCode (0-440B),
1099 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1100 With this in mind, we try not to modify these elements. */
1102 if (!ptt_read_sector (dev, 0, &s0))
1104 LegacyMBR_t *pmbr = s0;
1106 /* Zero out the legacy partitions. */
1107 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1109 pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1110 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1111 pmbr->PartitionRecord[0].StartSector = 1;
1112 pmbr->PartitionRecord[0].EndHead = 0xFE;
1113 pmbr->PartitionRecord[0].EndSector = 0xFF;
1114 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1115 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1116 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1117 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1119 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1121 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1128 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1129 GuidPartitionTableHeader_t **gpt_p)
1131 GPTDiskData *gpt_disk_data = disk->disk_specific;
1132 GuidPartitionTableHeader_t *gpt;
1134 *gpt_p = pth_new_zeroed (disk->dev);
1138 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1139 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1142 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1143 gpt->HeaderCRC32 = 0;
1148 PedSector ptes_size = gpt_disk_data->entry_count
1149 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1151 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1152 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1153 gpt->PartitionEntryLBA
1154 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1158 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1159 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1160 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1163 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1164 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1165 gpt->DiskGUID = gpt_disk_data->uuid;
1166 gpt->NumberOfPartitionEntries
1167 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1168 gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1169 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1172 if (pth_crc32 (disk->dev, gpt, &crc) != 0)
1175 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
1180 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1182 GPTPartitionData *gpt_part_data = part->disk_specific;
1185 PED_ASSERT (gpt_part_data != NULL, return);
1187 pte->PartitionTypeGuid = gpt_part_data->type;
1188 pte->UniquePartitionGuid = gpt_part_data->uuid;
1189 pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1190 pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1191 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1193 if (gpt_part_data->hidden)
1194 pte->Attributes.RequiredToFunction = 1;
1196 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1197 pte->PartitionName[i]
1198 = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1202 gpt_write (const PedDisk *disk)
1204 GPTDiskData *gpt_disk_data;
1205 GuidPartitionEntry_t *ptes;
1208 GuidPartitionTableHeader_t *gpt;
1212 PED_ASSERT (disk != NULL, goto error);
1213 PED_ASSERT (disk->dev != NULL, goto error);
1214 PED_ASSERT (disk->disk_specific != NULL, goto error);
1216 gpt_disk_data = disk->disk_specific;
1218 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1219 ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1222 memset (ptes, 0, ptes_size);
1223 for (part = ped_disk_next_partition (disk, NULL); part;
1224 part = ped_disk_next_partition (disk, part))
1226 if (part->type != 0)
1228 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1231 ptes_crc = efi_crc32 (ptes, ptes_size);
1233 /* Write protective MBR */
1234 if (!_write_pmbr (disk->dev))
1235 goto error_free_ptes;
1237 /* Write PTH and PTEs */
1238 if (_generate_header (disk, 0, ptes_crc, &gpt) != 0)
1239 goto error_free_ptes;
1240 if ((pth_raw = pth_get_raw (disk->dev, gpt)) == NULL)
1241 goto error_free_ptes;
1243 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1246 goto error_free_ptes;
1247 if (!ped_device_write (disk->dev, ptes, 2,
1248 ptes_size / disk->dev->sector_size))
1249 goto error_free_ptes;
1251 /* Write Alternate PTH & PTEs */
1252 if (_generate_header (disk, 1, ptes_crc, &gpt) != 0)
1253 goto error_free_ptes;
1254 if ((pth_raw = pth_get_raw (disk->dev, gpt)) == NULL)
1255 goto error_free_ptes;
1257 write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1260 goto error_free_ptes;
1261 if (!ped_device_write (disk->dev, ptes,
1262 disk->dev->length - 1 -
1263 ptes_size / disk->dev->sector_size,
1264 ptes_size / disk->dev->sector_size))
1265 goto error_free_ptes;
1268 return ped_device_sync (disk->dev);
1276 #endif /* !DISCOVER_ONLY */
1279 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1282 PedConstraint *constraint_exact;
1283 PED_ASSERT (disk != NULL, return 0);
1285 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1286 start, start + length - 1);
1290 constraint_exact = ped_constraint_exact (&part->geom);
1291 if (!ped_disk_add_partition (disk, part, constraint_exact))
1292 goto error_destroy_constraint;
1293 ped_constraint_destroy (constraint_exact);
1296 error_destroy_constraint:
1297 ped_constraint_destroy (constraint_exact);
1298 ped_partition_destroy (part);
1303 static PedPartition *
1304 gpt_partition_new (const PedDisk *disk,
1305 PedPartitionType part_type,
1306 const PedFileSystemType *fs_type, PedSector start,
1310 GPTPartitionData *gpt_part_data;
1312 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1319 gpt_part_data = part->disk_specific =
1320 ped_malloc (sizeof (GPTPartitionData));
1322 goto error_free_part;
1324 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1325 gpt_part_data->lvm = 0;
1326 gpt_part_data->raid = 0;
1327 gpt_part_data->boot = 0;
1328 gpt_part_data->bios_grub = 0;
1329 gpt_part_data->hp_service = 0;
1330 gpt_part_data->hidden = 0;
1331 gpt_part_data->msftres = 0;
1332 uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1333 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1334 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1338 _ped_partition_free (part);
1343 static PedPartition *
1344 gpt_partition_duplicate (const PedPartition *part)
1346 PedPartition *result;
1347 GPTPartitionData *part_data = part->disk_specific;
1348 GPTPartitionData *result_data;
1350 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1351 part->geom.start, part->geom.end);
1354 result->num = part->num;
1356 if (result->type != 0)
1359 result_data = result->disk_specific =
1360 ped_malloc (sizeof (GPTPartitionData));
1362 goto error_free_part;
1364 result_data->type = part_data->type;
1365 result_data->uuid = part_data->uuid;
1366 strcpy (result_data->name, part_data->name);
1370 _ped_partition_free (result);
1376 gpt_partition_destroy (PedPartition *part)
1378 if (part->type == 0)
1380 PED_ASSERT (part->disk_specific != NULL, return);
1381 free (part->disk_specific);
1384 _ped_partition_free (part);
1388 gpt_partition_set_system (PedPartition *part,
1389 const PedFileSystemType *fs_type)
1391 GPTPartitionData *gpt_part_data = part->disk_specific;
1393 PED_ASSERT (gpt_part_data != NULL, return 0);
1395 part->fs_type = fs_type;
1397 if (gpt_part_data->lvm)
1399 gpt_part_data->type = PARTITION_LVM_GUID;
1402 if (gpt_part_data->raid)
1404 gpt_part_data->type = PARTITION_RAID_GUID;
1407 if (gpt_part_data->boot)
1409 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1412 if (gpt_part_data->bios_grub)
1414 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1417 if (gpt_part_data->hp_service)
1419 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1422 if (gpt_part_data->msftres)
1424 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1430 if (strncmp (fs_type->name, "fat", 3) == 0
1431 || strcmp (fs_type->name, "ntfs") == 0)
1433 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1436 if (strncmp (fs_type->name, "hfs", 3) == 0)
1438 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1441 if (strstr (fs_type->name, "swap"))
1443 gpt_part_data->type = PARTITION_SWAP_GUID;
1448 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1452 /* Allocate metadata partitions for the GPTH and PTES */
1454 gpt_alloc_metadata (PedDisk *disk)
1456 PedSector gptlength, pteslength = 0;
1457 GPTDiskData *gpt_disk_data;
1459 PED_ASSERT (disk != NULL, return 0);
1460 PED_ASSERT (disk->dev != NULL, return 0);
1461 PED_ASSERT (disk->disk_specific != NULL, return 0);
1462 gpt_disk_data = disk->disk_specific;
1464 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1465 disk->dev->sector_size);
1466 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1467 * sizeof (GuidPartitionEntry_t),
1468 disk->dev->sector_size);
1470 /* metadata at the start of the disk includes the MBR */
1471 if (!add_metadata_part (disk, GPT_PMBR_LBA,
1472 GPT_PMBR_SECTORS + gptlength + pteslength))
1475 /* metadata at the end of the disk */
1476 if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1477 gptlength + pteslength))
1483 /* Does nothing, as the read/new/destroy functions maintain part->num */
1485 gpt_partition_enumerate (PedPartition *part)
1487 GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1490 /* never change the partition numbers */
1491 if (part->num != -1)
1494 for (i = 1; i <= gpt_disk_data->entry_count; i++)
1496 if (!ped_disk_get_partition (part->disk, i))
1503 PED_ASSERT (0, return 0);
1505 return 0; /* used if debug is disabled */
1509 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1511 GPTPartitionData *gpt_part_data;
1512 PED_ASSERT (part != NULL, return 0);
1513 PED_ASSERT (part->disk_specific != NULL, return 0);
1514 gpt_part_data = part->disk_specific;
1518 case PED_PARTITION_BOOT:
1519 gpt_part_data->boot = state;
1522 = gpt_part_data->lvm
1523 = gpt_part_data->bios_grub
1524 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1525 return gpt_partition_set_system (part, part->fs_type);
1526 case PED_PARTITION_BIOS_GRUB:
1527 gpt_part_data->bios_grub = state;
1530 = gpt_part_data->lvm
1531 = gpt_part_data->boot
1532 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1533 return gpt_partition_set_system (part, part->fs_type);
1534 case PED_PARTITION_RAID:
1535 gpt_part_data->raid = state;
1538 = gpt_part_data->lvm
1539 = gpt_part_data->bios_grub
1540 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1541 return gpt_partition_set_system (part, part->fs_type);
1542 case PED_PARTITION_LVM:
1543 gpt_part_data->lvm = state;
1546 = gpt_part_data->raid
1547 = gpt_part_data->bios_grub
1548 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1549 return gpt_partition_set_system (part, part->fs_type);
1550 case PED_PARTITION_HPSERVICE:
1551 gpt_part_data->hp_service = state;
1554 = gpt_part_data->raid
1555 = gpt_part_data->lvm
1556 = gpt_part_data->bios_grub = gpt_part_data->msftres = 0;
1557 return gpt_partition_set_system (part, part->fs_type);
1558 case PED_PARTITION_MSFT_RESERVED:
1559 gpt_part_data->msftres = state;
1562 = gpt_part_data->raid
1563 = gpt_part_data->lvm
1564 = gpt_part_data->bios_grub = gpt_part_data->hp_service = 0;
1565 return gpt_partition_set_system (part, part->fs_type);
1566 case PED_PARTITION_HIDDEN:
1567 gpt_part_data->hidden = state;
1569 case PED_PARTITION_SWAP:
1570 case PED_PARTITION_ROOT:
1571 case PED_PARTITION_LBA:
1579 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1581 GPTPartitionData *gpt_part_data;
1582 PED_ASSERT (part->disk_specific != NULL, return 0);
1583 gpt_part_data = part->disk_specific;
1587 case PED_PARTITION_RAID:
1588 return gpt_part_data->raid;
1589 case PED_PARTITION_LVM:
1590 return gpt_part_data->lvm;
1591 case PED_PARTITION_BOOT:
1592 return gpt_part_data->boot;
1593 case PED_PARTITION_BIOS_GRUB:
1594 return gpt_part_data->bios_grub;
1595 case PED_PARTITION_HPSERVICE:
1596 return gpt_part_data->hp_service;
1597 case PED_PARTITION_MSFT_RESERVED:
1598 return gpt_part_data->msftres;
1599 case PED_PARTITION_HIDDEN:
1600 return gpt_part_data->hidden;
1601 case PED_PARTITION_SWAP:
1602 case PED_PARTITION_LBA:
1603 case PED_PARTITION_ROOT:
1611 gpt_partition_is_flag_available (const PedPartition *part,
1612 PedPartitionFlag flag)
1616 case PED_PARTITION_RAID:
1617 case PED_PARTITION_LVM:
1618 case PED_PARTITION_BOOT:
1619 case PED_PARTITION_BIOS_GRUB:
1620 case PED_PARTITION_HPSERVICE:
1621 case PED_PARTITION_MSFT_RESERVED:
1622 case PED_PARTITION_HIDDEN:
1624 case PED_PARTITION_SWAP:
1625 case PED_PARTITION_ROOT:
1626 case PED_PARTITION_LBA:
1634 gpt_partition_set_name (PedPartition *part, const char *name)
1636 GPTPartitionData *gpt_part_data = part->disk_specific;
1638 strncpy (gpt_part_data->name, name, 36);
1639 gpt_part_data->name[36] = 0;
1643 gpt_partition_get_name (const PedPartition *part)
1645 GPTPartitionData *gpt_part_data = part->disk_specific;
1646 return gpt_part_data->name;
1650 gpt_get_max_primary_partition_count (const PedDisk *disk)
1652 const GPTDiskData *gpt_disk_data = disk->disk_specific;
1653 return gpt_disk_data->entry_count;
1657 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1658 * According to the specs the first LBA (LBA0) is not relevant (it exists
1659 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1660 * header. The header is as big as the block size. After the header we
1661 * find the Entry array. Each element of said array, describes each
1662 * partition. One can have as much elements as can fit between the end of
1663 * the second LBA (where the header ends) and the FirstUsableLBA.
1664 * FirstUsableLBA is the first logical block that is used for contents
1665 * and is defined in header.
1667 * /---------------------------------------------------\
1668 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1670 * \---------------------------------------------------/
1672 * /----------/ \----------\
1673 * /-----------------------------------------\
1674 * | E1 | E2 | E3 |...............| EN |
1675 * \-----------------------------------------/
1677 * The number of possible partitions or supported partitions is:
1678 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1679 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1682 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1684 GuidPartitionTableHeader_t *pth = NULL;
1685 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1687 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1688 || ped_device_read (disk->dev, pth_raw,
1689 disk->dev->length, GPT_HEADER_SECTORS))
1690 pth = pth_new_from_raw (disk->dev, pth_raw);
1696 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1697 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1702 static PedConstraint *
1703 _non_metadata_constraint (const PedDisk *disk)
1705 GPTDiskData *gpt_disk_data = disk->disk_specific;
1707 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1711 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1713 PED_ASSERT (part != NULL, return 0);
1715 if (_ped_partition_attempt_align (part, constraint,
1716 _non_metadata_constraint (part->disk)))
1719 #ifndef DISCOVER_ONLY
1720 ped_exception_throw (PED_EXCEPTION_ERROR,
1721 PED_EXCEPTION_CANCEL,
1722 _("Unable to satisfy all constraints on the partition."));
1728 gpt_partition_check (const PedPartition *part)
1733 #ifdef DISCOVER_ONLY
1734 # define NULL_IF_DISCOVER_ONLY(val) NULL
1736 # define NULL_IF_DISCOVER_ONLY(val) val
1739 static PedDiskOps gpt_disk_ops =
1742 clobber: NULL_IF_DISCOVER_ONLY (gpt_clobber),
1744 duplicate: gpt_duplicate,
1747 write: NULL_IF_DISCOVER_ONLY (gpt_write),
1748 partition_new: gpt_partition_new,
1749 partition_duplicate: gpt_partition_duplicate,
1750 partition_destroy: gpt_partition_destroy,
1751 partition_set_system: gpt_partition_set_system,
1752 partition_set_flag: gpt_partition_set_flag,
1753 partition_get_flag: gpt_partition_get_flag,
1754 partition_is_flag_available: gpt_partition_is_flag_available,
1755 partition_set_name: gpt_partition_set_name,
1756 partition_get_name: gpt_partition_get_name,
1757 partition_align: gpt_partition_align,
1758 partition_enumerate: gpt_partition_enumerate,
1759 partition_check: gpt_partition_check,
1760 alloc_metadata: gpt_alloc_metadata,
1761 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1762 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1765 static PedDiskType gpt_disk_type =
1770 features: PED_DISK_TYPE_PARTITION_NAME
1774 ped_disk_gpt_init ()
1776 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1777 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1779 ped_disk_type_register (&gpt_disk_type);
1783 ped_disk_gpt_done ()
1785 ped_disk_type_unregister (&gpt_disk_type);