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 static inline uint32_t
395 pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
397 PED_ASSERT (dev != NULL, return 0);
398 PED_ASSERT (pth != NULL, return 0);
400 uint8_t *pth_raw = pth_get_raw (dev, pth);
403 uint32_t crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
411 guid_cmp (efi_guid_t left, efi_guid_t right)
413 return memcmp (&left, &right, sizeof (efi_guid_t));
416 /* checks if 'mbr' is a protective MBR partition table */
418 _pmbr_is_valid (const LegacyMBR_t *mbr)
422 PED_ASSERT (mbr != NULL, return 0);
424 if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
426 for (i = 0; i < 4; i++)
428 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
435 gpt_probe (const PedDevice *dev)
437 GuidPartitionTableHeader_t *gpt = NULL;
438 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
439 int gpt_sig_found = 0;
441 PED_ASSERT (dev != NULL, return 0);
443 if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
444 || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
446 gpt = pth_new_from_raw (dev, pth_raw);
447 if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
459 if (!ptt_read_sector (dev, 0, &label))
463 if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
465 int ex_status = ped_exception_throw
466 (PED_EXCEPTION_WARNING,
467 PED_EXCEPTION_YES_NO,
468 _("%s contains GPT signatures, indicating that it has "
469 "a GPT table. However, it does not have a valid "
470 "fake msdos partition table, as it should. Perhaps "
471 "it was corrupted -- possibly by a program that "
472 "doesn't understand GPT partition tables. Or "
473 "perhaps you deleted the GPT table, and are now "
474 "using an msdos partition table. Is this a GPT "
477 if (ex_status == PED_EXCEPTION_NO)
485 #ifndef DISCOVER_ONLY
486 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
488 gpt_clobber (PedDevice *dev)
490 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
491 GuidPartitionTableHeader_t *gpt;
493 PED_ASSERT (dev != NULL, return 0);
496 * TO DISCUSS: check whether checksum is correct?
497 * If not, we might get a wrong AlternateLBA field and destroy
498 * one sector of random data.
500 if (!ped_device_read (dev, pth_raw,
501 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
507 gpt = pth_new_from_raw (dev, pth_raw);
510 if (!ptt_clear_sectors (dev, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
511 goto error_free_with_gpt;
512 if (!ptt_clear_sectors (dev, GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
513 goto error_free_with_gpt;
514 if (!ptt_clear_sectors (dev, dev->length - GPT_HEADER_SECTORS,
516 goto error_free_with_gpt;
518 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1)
520 if (!ped_device_write (dev, gpt,
521 PED_LE64_TO_CPU (gpt->AlternateLBA),
534 #endif /* !DISCOVER_ONLY */
537 gpt_alloc (const PedDevice *dev)
540 GPTDiskData *gpt_disk_data;
541 PedSector data_start, data_end;
543 disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
546 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
547 if (!disk->disk_specific)
548 goto error_free_disk;
550 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
551 data_end = dev->length - 2
552 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
553 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
554 data_end - data_start + 1);
555 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
556 uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
557 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
567 gpt_duplicate (const PedDisk *disk)
570 GPTDiskData *new_disk_data;
571 GPTDiskData *old_disk_data;
573 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
577 old_disk_data = disk->disk_specific;
578 new_disk_data = new_disk->disk_specific;
580 ped_geometry_init (&new_disk_data->data_area, disk->dev,
581 old_disk_data->data_area.start,
582 old_disk_data->data_area.length);
583 new_disk_data->entry_count = old_disk_data->entry_count;
584 new_disk_data->uuid = old_disk_data->uuid;
589 gpt_free (PedDisk *disk)
591 ped_disk_delete_all (disk);
592 free (disk->disk_specific);
593 _ped_disk_free (disk);
596 /* Given GUID Partition table header, GPT, read its partition array
597 entries from DISK into malloc'd storage. Set *PTES_BYTES to the
598 number of bytes required. Upon success, return a pointer to the
599 resulting buffer. Otherwise, set errno and return NULL. */
601 gpt_read_PE_array (PedDisk const *disk, GuidPartitionTableHeader_t const *gpt,
604 GPTDiskData *gpt_disk_data = disk->disk_specific;
605 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
606 *ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
607 size_t ptes_sectors = ped_div_round_up (*ptes_bytes,
608 disk->dev->sector_size);
610 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
615 void *ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
619 if (!ped_device_read (disk->dev, ptes,
620 PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
622 int saved_errno = errno;
632 _header_is_valid (const PedDevice *dev, GuidPartitionTableHeader_t *gpt,
635 uint32_t crc, origcrc;
637 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
640 * "While the GUID Partition Table Header's size may increase
641 * in the future it cannot span more than one block on the
642 * device." EFI Specification, version 1.10, 11.2.2.1
644 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
645 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
648 /* The SizeOfPartitionEntry must be a multiple of 8 and
649 no smaller than the size of the PartitionEntry structure.
650 We also require that be no larger than 1/16th of UINT32_MAX,
651 as an additional sanity check. */
652 uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
654 || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
657 if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
660 PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
661 /* The backup table's AlternateLBA must be 1. */
662 if (my_lba != 1 && alt_lba != 1)
665 /* The alt_lba must never be the same as my_lba. */
666 if (alt_lba == my_lba)
669 origcrc = gpt->HeaderCRC32;
670 gpt->HeaderCRC32 = 0;
671 crc = pth_crc32 (dev, gpt);
672 gpt->HeaderCRC32 = origcrc;
674 return crc == PED_LE32_TO_CPU (origcrc);
678 _parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
681 GPTDiskData *gpt_disk_data = disk->disk_specific;
682 PedSector first_usable;
683 PedSector last_usable;
684 PedSector last_usable_if_grown, last_usable_min_default;
685 static int asked_already;
687 // PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
689 #ifndef DISCOVER_ONLY
690 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
692 if (ped_exception_throw
693 (PED_EXCEPTION_WARNING,
694 PED_EXCEPTION_IGNORE_CANCEL,
695 _("The format of the GPT partition table is version "
696 "%x, which is newer than what Parted can "
697 "recognise. Please tell us! bug-parted@gnu.org"),
698 PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
703 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
704 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
706 /* Need to check whether the volume has grown, the LastUsableLBA is
707 normally set to disk->dev->length - 2 - ptes_size (at least for parted
708 created volumes), where ptes_size is the number of entries *
709 size of each entry / sector size or 16k / sector size, whatever the greater.
710 If the volume has grown, offer the user the chance to use the new
711 space or continue with the current usable area. Only ask once per
712 parted invocation. */
715 = (disk->dev->length - 2 -
716 ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
717 (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
718 disk->dev->sector_size));
720 last_usable_min_default = disk->dev->length - 2 -
721 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
723 if (last_usable_if_grown > last_usable_min_default)
725 last_usable_if_grown = last_usable_min_default;
728 PED_ASSERT (last_usable > first_usable, return 0);
729 PED_ASSERT (last_usable <= disk->dev->length, return 0);
731 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
732 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
734 if (!asked_already && last_usable < last_usable_if_grown)
737 PedExceptionOption q;
739 q = ped_exception_throw
740 (PED_EXCEPTION_WARNING,
741 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
742 _("Not all of the space available to %s appears "
743 "to be used, you can fix the GPT to use all of the "
744 "space (an extra %llu blocks) or continue with the "
745 "current setting? "), disk->dev->path,
746 (uint64_t) (last_usable_if_grown - last_usable));
748 if (q == PED_EXCEPTION_FIX)
750 last_usable = last_usable_if_grown;
753 else if (q != PED_EXCEPTION_UNHANDLED)
759 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
760 first_usable, last_usable - first_usable + 1);
762 gpt_disk_data->entry_count
763 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
764 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
765 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
767 gpt_disk_data->uuid = gpt->DiskGUID;
772 static PedPartition *
773 _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
776 GPTPartitionData *gpt_part_data;
779 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
780 PED_LE64_TO_CPU (pte->StartingLBA),
781 PED_LE64_TO_CPU (pte->EndingLBA));
785 gpt_part_data = part->disk_specific;
786 gpt_part_data->type = pte->PartitionTypeGuid;
787 gpt_part_data->uuid = pte->UniquePartitionGuid;
788 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
789 gpt_part_data->name[i] =
790 (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
791 gpt_part_data->name[i] = 0;
793 gpt_part_data->lvm = gpt_part_data->raid
794 = gpt_part_data->boot = gpt_part_data->hp_service
795 = gpt_part_data->hidden = gpt_part_data->msftres
796 = gpt_part_data->bios_grub = 0;
798 if (pte->Attributes.RequiredToFunction & 0x1)
799 gpt_part_data->hidden = 1;
801 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
802 gpt_part_data->boot = 1;
803 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
804 gpt_part_data->bios_grub = 1;
805 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
806 gpt_part_data->raid = 1;
807 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
808 gpt_part_data->lvm = 1;
809 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
810 gpt_part_data->hp_service = 1;
811 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
812 gpt_part_data->msftres = 1;
817 /* Read the primary GPT at sector 1 of DEV.
818 Verify its CRC and that of its partition entry array.
819 If they are valid, read the backup GPT specified by AlternateLBA.
820 If not, read the backup GPT in the last sector of the disk.
821 Return 1 if any read fails.
822 Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
823 Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
824 If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
825 number in which it was found. */
827 gpt_read_headers (PedDevice *dev,
828 GuidPartitionTableHeader_t **primary_gpt,
829 GuidPartitionTableHeader_t **backup_gpt,
830 PedSector *backup_sector_num_p)
836 if (!ptt_read_sector (dev, 1, &s1))
839 GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
843 GuidPartitionTableHeader_t *pri = t;
845 bool valid_primary = _header_is_valid (dev, pri, 1);
849 PedSector backup_sector_num =
851 ? PED_LE64_TO_CPU (pri->AlternateLBA)
855 if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
857 t = pth_new_from_raw (dev, s_bak);
861 GuidPartitionTableHeader_t *bak = t;
862 if (_header_is_valid (dev, bak, backup_sector_num))
865 *backup_sector_num_p = backup_sector_num;
871 /************************************************************
872 * Intel is changing the EFI Spec. (after v1.02) to say that a
873 * disk is considered to have a GPT label only if the GPT
874 * structures are correct, and the MBR is actually a Protective
875 * MBR (has one 0xEE type partition).
876 * Problem occurs when a GPT-partitioned disk is then
877 * edited with a legacy (non-GPT-aware) application, such as
878 * fdisk (which doesn't generally erase the PGPT or AGPT).
879 * How should such a disk get handled? As a GPT disk (throwing
880 * away the fdisk changes), or as an MSDOS disk (throwing away
881 * the GPT information). Previously, I've taken the GPT-is-right,
882 * MBR is wrong, approach, to stay consistent with the EFI Spec.
883 * Intel disagrees, saying the disk should then be treated
884 * as having a msdos label, not a GPT label. If this is true,
885 * then what's the point of having an AGPT, since if the PGPT
886 * is screwed up, likely the PMBR is too, and the PMBR becomes
887 * a single point of failure.
888 * So, in the Linux kernel, I'm going to test for PMBR, and
889 * warn if it's not there, and treat the disk as MSDOS, with a note
890 * for users to use Parted to "fix up" their disk if they
891 * really want it to be considered GPT.
892 ************************************************************/
894 gpt_read (PedDisk *disk)
896 GPTDiskData *gpt_disk_data = disk->disk_specific;
898 #ifndef DISCOVER_ONLY
902 ped_disk_delete_all (disk);
904 /* motivation: let the user decide about the pmbr... during
905 ped_disk_probe(), they probably didn't get a choice... */
906 if (!gpt_probe (disk->dev))
909 GuidPartitionTableHeader_t *gpt = NULL;
910 GuidPartitionTableHeader_t *primary_gpt;
911 GuidPartitionTableHeader_t *backup_gpt;
912 PedSector backup_sector_num;
913 int read_failure = gpt_read_headers (disk->dev, &primary_gpt, &backup_gpt,
917 /* This includes the case in which there used to be a GPT partition
918 table here, with an alternate LBA that extended beyond the current
919 end-of-device. It's treated as a non-match. */
921 /* Another possibility:
922 The primary header is ok, but backup is corrupt.
923 In the UEFI spec, this means the primary GUID table
924 is officially invalid. */
925 pth_free (backup_gpt);
926 pth_free (primary_gpt);
930 if (primary_gpt && backup_gpt)
932 /* Both are valid. */
933 if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
935 #ifndef DISCOVER_ONLY
936 switch (ped_exception_throw
937 (PED_EXCEPTION_ERROR,
938 (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
939 | PED_EXCEPTION_IGNORE),
940 _("The backup GPT table is not at the end of the disk, as it "
941 "should be. This might mean that another operating system "
942 "believes the disk is smaller. Fix, by moving the backup "
943 "to the end (and removing the old backup)?")))
945 case PED_EXCEPTION_CANCEL:
947 case PED_EXCEPTION_FIX:
948 ptt_clear_sectors (disk->dev,
949 PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
955 #endif /* !DISCOVER_ONLY */
958 pth_free (backup_gpt);
960 else if (!primary_gpt && !backup_gpt)
962 /* Both are corrupt. */
963 ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
964 _("Both the primary and backup GPT tables "
965 "are corrupt. Try making a fresh table, "
966 "and using Parted's rescue feature to "
967 "recover partitions."));
970 else if (primary_gpt && !backup_gpt)
972 /* The primary header is ok, but backup is corrupt. */
973 if (ped_exception_throw
974 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
975 _("The backup GPT table is corrupt, but the "
976 "primary appears OK, so that will be used."))
977 == PED_EXCEPTION_CANCEL)
982 else /* !primary_gpt && backup_gpt */
984 /* primary GPT corrupt, backup is ok. */
985 if (ped_exception_throw
986 (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
987 _("The primary GPT table is corrupt, but the "
988 "backup appears OK, so that will be used."))
989 == PED_EXCEPTION_CANCEL)
997 if (!_parse_header (disk, gpt, &write_back))
1001 void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
1003 goto error_free_gpt;
1005 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
1006 if (ptes_crc != gpt->PartitionEntryArrayCRC32)
1009 (PED_EXCEPTION_ERROR,
1010 PED_EXCEPTION_CANCEL,
1011 _("primary partition table array CRC mismatch"));
1012 goto error_free_ptes;
1015 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
1016 for (i = 0; i < gpt_disk_data->entry_count; i++)
1018 GuidPartitionEntry_t *pte
1019 = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
1021 PedConstraint *constraint_exact;
1023 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
1026 part = _parse_part_entry (disk, pte);
1028 goto error_delete_all;
1030 part->fs_type = ped_file_system_probe (&part->geom);
1033 constraint_exact = ped_constraint_exact (&part->geom);
1034 if (!ped_disk_add_partition (disk, part, constraint_exact))
1036 ped_partition_destroy (part);
1037 goto error_delete_all;
1039 ped_constraint_destroy (constraint_exact);
1043 #ifndef DISCOVER_ONLY
1045 ped_disk_commit_to_dev (disk);
1052 ped_disk_delete_all (disk);
1056 pth_free (primary_gpt);
1057 pth_free (backup_gpt);
1063 #ifndef DISCOVER_ONLY
1064 /* Write the protective MBR (to keep DOS happy) */
1066 _write_pmbr (PedDevice *dev)
1068 /* The UEFI spec is not clear about what to do with the following
1069 elements of the Protective MBR (pmbr): BootCode (0-440B),
1070 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1071 With this in mind, we try not to modify these elements. */
1073 if (!ptt_read_sector (dev, 0, &s0))
1075 LegacyMBR_t *pmbr = s0;
1077 /* Zero out the legacy partitions. */
1078 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1080 pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1081 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1082 pmbr->PartitionRecord[0].StartSector = 1;
1083 pmbr->PartitionRecord[0].EndHead = 0xFE;
1084 pmbr->PartitionRecord[0].EndSector = 0xFF;
1085 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1086 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1087 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1088 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1090 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1092 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1099 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1100 GuidPartitionTableHeader_t **gpt_p)
1102 GPTDiskData *gpt_disk_data = disk->disk_specific;
1103 GuidPartitionTableHeader_t *gpt;
1105 *gpt_p = pth_new_zeroed (disk->dev);
1109 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1110 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1113 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1114 gpt->HeaderCRC32 = 0;
1119 PedSector ptes_size = gpt_disk_data->entry_count
1120 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1122 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1123 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1124 gpt->PartitionEntryLBA
1125 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1129 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1130 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1131 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1134 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1135 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1136 gpt->DiskGUID = gpt_disk_data->uuid;
1137 gpt->NumberOfPartitionEntries
1138 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1139 gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1140 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1141 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1145 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1147 GPTPartitionData *gpt_part_data = part->disk_specific;
1150 PED_ASSERT (gpt_part_data != NULL, return);
1152 pte->PartitionTypeGuid = gpt_part_data->type;
1153 pte->UniquePartitionGuid = gpt_part_data->uuid;
1154 pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1155 pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1156 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1158 if (gpt_part_data->hidden)
1159 pte->Attributes.RequiredToFunction = 1;
1161 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1162 pte->PartitionName[i]
1163 = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1167 gpt_write (const PedDisk *disk)
1169 GPTDiskData *gpt_disk_data;
1170 GuidPartitionEntry_t *ptes;
1173 GuidPartitionTableHeader_t *gpt;
1177 PED_ASSERT (disk != NULL, goto error);
1178 PED_ASSERT (disk->dev != NULL, goto error);
1179 PED_ASSERT (disk->disk_specific != NULL, goto error);
1181 gpt_disk_data = disk->disk_specific;
1183 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1184 ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1187 memset (ptes, 0, ptes_size);
1188 for (part = ped_disk_next_partition (disk, NULL); part;
1189 part = ped_disk_next_partition (disk, part))
1191 if (part->type != 0)
1193 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1196 ptes_crc = efi_crc32 (ptes, ptes_size);
1198 /* Write protective MBR */
1199 if (!_write_pmbr (disk->dev))
1200 goto error_free_ptes;
1202 /* Write PTH and PTEs */
1203 _generate_header (disk, 0, ptes_crc, &gpt);
1204 if ((pth_raw = pth_get_raw (disk->dev, gpt)) == NULL)
1205 goto error_free_ptes;
1207 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1210 goto error_free_ptes;
1211 if (!ped_device_write (disk->dev, ptes, 2,
1212 ptes_size / disk->dev->sector_size))
1213 goto error_free_ptes;
1215 /* Write Alternate PTH & PTEs */
1216 _generate_header (disk, 1, ptes_crc, &gpt);
1217 if ((pth_raw = pth_get_raw (disk->dev, gpt)) == NULL)
1218 goto error_free_ptes;
1220 write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1223 goto error_free_ptes;
1224 if (!ped_device_write (disk->dev, ptes,
1225 disk->dev->length - 1 -
1226 ptes_size / disk->dev->sector_size,
1227 ptes_size / disk->dev->sector_size))
1228 goto error_free_ptes;
1231 return ped_device_sync (disk->dev);
1239 #endif /* !DISCOVER_ONLY */
1242 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1245 PedConstraint *constraint_exact;
1246 PED_ASSERT (disk != NULL, return 0);
1248 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1249 start, start + length - 1);
1253 constraint_exact = ped_constraint_exact (&part->geom);
1254 if (!ped_disk_add_partition (disk, part, constraint_exact))
1255 goto error_destroy_constraint;
1256 ped_constraint_destroy (constraint_exact);
1259 error_destroy_constraint:
1260 ped_constraint_destroy (constraint_exact);
1261 ped_partition_destroy (part);
1266 static PedPartition *
1267 gpt_partition_new (const PedDisk *disk,
1268 PedPartitionType part_type,
1269 const PedFileSystemType *fs_type, PedSector start,
1273 GPTPartitionData *gpt_part_data;
1275 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1282 gpt_part_data = part->disk_specific =
1283 ped_malloc (sizeof (GPTPartitionData));
1285 goto error_free_part;
1287 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1288 gpt_part_data->lvm = 0;
1289 gpt_part_data->raid = 0;
1290 gpt_part_data->boot = 0;
1291 gpt_part_data->bios_grub = 0;
1292 gpt_part_data->hp_service = 0;
1293 gpt_part_data->hidden = 0;
1294 gpt_part_data->msftres = 0;
1295 uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1296 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1297 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1301 _ped_partition_free (part);
1306 static PedPartition *
1307 gpt_partition_duplicate (const PedPartition *part)
1309 PedPartition *result;
1310 GPTPartitionData *part_data = part->disk_specific;
1311 GPTPartitionData *result_data;
1313 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1314 part->geom.start, part->geom.end);
1317 result->num = part->num;
1319 if (result->type != 0)
1322 result_data = result->disk_specific =
1323 ped_malloc (sizeof (GPTPartitionData));
1325 goto error_free_part;
1327 result_data->type = part_data->type;
1328 result_data->uuid = part_data->uuid;
1329 strcpy (result_data->name, part_data->name);
1333 _ped_partition_free (result);
1339 gpt_partition_destroy (PedPartition *part)
1341 if (part->type == 0)
1343 PED_ASSERT (part->disk_specific != NULL, return);
1344 free (part->disk_specific);
1347 _ped_partition_free (part);
1351 gpt_partition_set_system (PedPartition *part,
1352 const PedFileSystemType *fs_type)
1354 GPTPartitionData *gpt_part_data = part->disk_specific;
1356 PED_ASSERT (gpt_part_data != NULL, return 0);
1358 part->fs_type = fs_type;
1360 if (gpt_part_data->lvm)
1362 gpt_part_data->type = PARTITION_LVM_GUID;
1365 if (gpt_part_data->raid)
1367 gpt_part_data->type = PARTITION_RAID_GUID;
1370 if (gpt_part_data->boot)
1372 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1375 if (gpt_part_data->bios_grub)
1377 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1380 if (gpt_part_data->hp_service)
1382 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1385 if (gpt_part_data->msftres)
1387 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1393 if (strncmp (fs_type->name, "fat", 3) == 0
1394 || strcmp (fs_type->name, "ntfs") == 0)
1396 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1399 if (strncmp (fs_type->name, "hfs", 3) == 0)
1401 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1404 if (strstr (fs_type->name, "swap"))
1406 gpt_part_data->type = PARTITION_SWAP_GUID;
1411 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1415 /* Allocate metadata partitions for the GPTH and PTES */
1417 gpt_alloc_metadata (PedDisk *disk)
1419 PedSector gptlength, pteslength = 0;
1420 GPTDiskData *gpt_disk_data;
1422 PED_ASSERT (disk != NULL, return 0);
1423 PED_ASSERT (disk->dev != NULL, return 0);
1424 PED_ASSERT (disk->disk_specific != NULL, return 0);
1425 gpt_disk_data = disk->disk_specific;
1427 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1428 disk->dev->sector_size);
1429 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1430 * sizeof (GuidPartitionEntry_t),
1431 disk->dev->sector_size);
1433 /* metadata at the start of the disk includes the MBR */
1434 if (!add_metadata_part (disk, GPT_PMBR_LBA,
1435 GPT_PMBR_SECTORS + gptlength + pteslength))
1438 /* metadata at the end of the disk */
1439 if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1440 gptlength + pteslength))
1446 /* Does nothing, as the read/new/destroy functions maintain part->num */
1448 gpt_partition_enumerate (PedPartition *part)
1450 GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1453 /* never change the partition numbers */
1454 if (part->num != -1)
1457 for (i = 1; i <= gpt_disk_data->entry_count; i++)
1459 if (!ped_disk_get_partition (part->disk, i))
1466 PED_ASSERT (0, return 0);
1468 return 0; /* used if debug is disabled */
1472 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1474 GPTPartitionData *gpt_part_data;
1475 PED_ASSERT (part != NULL, return 0);
1476 PED_ASSERT (part->disk_specific != NULL, return 0);
1477 gpt_part_data = part->disk_specific;
1481 case PED_PARTITION_BOOT:
1482 gpt_part_data->boot = state;
1485 = gpt_part_data->lvm
1486 = gpt_part_data->bios_grub
1487 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1488 return gpt_partition_set_system (part, part->fs_type);
1489 case PED_PARTITION_BIOS_GRUB:
1490 gpt_part_data->bios_grub = state;
1493 = gpt_part_data->lvm
1494 = gpt_part_data->boot
1495 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1496 return gpt_partition_set_system (part, part->fs_type);
1497 case PED_PARTITION_RAID:
1498 gpt_part_data->raid = state;
1501 = gpt_part_data->lvm
1502 = gpt_part_data->bios_grub
1503 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1504 return gpt_partition_set_system (part, part->fs_type);
1505 case PED_PARTITION_LVM:
1506 gpt_part_data->lvm = state;
1509 = gpt_part_data->raid
1510 = gpt_part_data->bios_grub
1511 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1512 return gpt_partition_set_system (part, part->fs_type);
1513 case PED_PARTITION_HPSERVICE:
1514 gpt_part_data->hp_service = state;
1517 = gpt_part_data->raid
1518 = gpt_part_data->lvm
1519 = gpt_part_data->bios_grub = gpt_part_data->msftres = 0;
1520 return gpt_partition_set_system (part, part->fs_type);
1521 case PED_PARTITION_MSFT_RESERVED:
1522 gpt_part_data->msftres = state;
1525 = gpt_part_data->raid
1526 = gpt_part_data->lvm
1527 = gpt_part_data->bios_grub = gpt_part_data->hp_service = 0;
1528 return gpt_partition_set_system (part, part->fs_type);
1529 case PED_PARTITION_HIDDEN:
1530 gpt_part_data->hidden = state;
1532 case PED_PARTITION_SWAP:
1533 case PED_PARTITION_ROOT:
1534 case PED_PARTITION_LBA:
1542 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1544 GPTPartitionData *gpt_part_data;
1545 PED_ASSERT (part->disk_specific != NULL, return 0);
1546 gpt_part_data = part->disk_specific;
1550 case PED_PARTITION_RAID:
1551 return gpt_part_data->raid;
1552 case PED_PARTITION_LVM:
1553 return gpt_part_data->lvm;
1554 case PED_PARTITION_BOOT:
1555 return gpt_part_data->boot;
1556 case PED_PARTITION_BIOS_GRUB:
1557 return gpt_part_data->bios_grub;
1558 case PED_PARTITION_HPSERVICE:
1559 return gpt_part_data->hp_service;
1560 case PED_PARTITION_MSFT_RESERVED:
1561 return gpt_part_data->msftres;
1562 case PED_PARTITION_HIDDEN:
1563 return gpt_part_data->hidden;
1564 case PED_PARTITION_SWAP:
1565 case PED_PARTITION_LBA:
1566 case PED_PARTITION_ROOT:
1574 gpt_partition_is_flag_available (const PedPartition *part,
1575 PedPartitionFlag flag)
1579 case PED_PARTITION_RAID:
1580 case PED_PARTITION_LVM:
1581 case PED_PARTITION_BOOT:
1582 case PED_PARTITION_BIOS_GRUB:
1583 case PED_PARTITION_HPSERVICE:
1584 case PED_PARTITION_MSFT_RESERVED:
1585 case PED_PARTITION_HIDDEN:
1587 case PED_PARTITION_SWAP:
1588 case PED_PARTITION_ROOT:
1589 case PED_PARTITION_LBA:
1597 gpt_partition_set_name (PedPartition *part, const char *name)
1599 GPTPartitionData *gpt_part_data = part->disk_specific;
1601 strncpy (gpt_part_data->name, name, 36);
1602 gpt_part_data->name[36] = 0;
1606 gpt_partition_get_name (const PedPartition *part)
1608 GPTPartitionData *gpt_part_data = part->disk_specific;
1609 return gpt_part_data->name;
1613 gpt_get_max_primary_partition_count (const PedDisk *disk)
1615 const GPTDiskData *gpt_disk_data = disk->disk_specific;
1616 return gpt_disk_data->entry_count;
1620 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1621 * According to the specs the first LBA (LBA0) is not relevant (it exists
1622 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1623 * header. The header is as big as the block size. After the header we
1624 * find the Entry array. Each element of said array, describes each
1625 * partition. One can have as much elements as can fit between the end of
1626 * the second LBA (where the header ends) and the FirstUsableLBA.
1627 * FirstUsableLBA is the first logical block that is used for contents
1628 * and is defined in header.
1630 * /---------------------------------------------------\
1631 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1633 * \---------------------------------------------------/
1635 * /----------/ \----------\
1636 * /-----------------------------------------\
1637 * | E1 | E2 | E3 |...............| EN |
1638 * \-----------------------------------------/
1640 * The number of possible partitions or supported partitions is:
1641 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1642 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1645 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1647 GuidPartitionTableHeader_t *pth = NULL;
1648 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1650 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1651 || ped_device_read (disk->dev, pth_raw,
1652 disk->dev->length, GPT_HEADER_SECTORS))
1653 pth = pth_new_from_raw (disk->dev, pth_raw);
1659 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1660 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1665 static PedConstraint *
1666 _non_metadata_constraint (const PedDisk *disk)
1668 GPTDiskData *gpt_disk_data = disk->disk_specific;
1670 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1674 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1676 PED_ASSERT (part != NULL, return 0);
1678 if (_ped_partition_attempt_align (part, constraint,
1679 _non_metadata_constraint (part->disk)))
1682 #ifndef DISCOVER_ONLY
1683 ped_exception_throw (PED_EXCEPTION_ERROR,
1684 PED_EXCEPTION_CANCEL,
1685 _("Unable to satisfy all constraints on the partition."));
1691 gpt_partition_check (const PedPartition *part)
1696 #ifdef DISCOVER_ONLY
1697 # define NULL_IF_DISCOVER_ONLY(val) NULL
1699 # define NULL_IF_DISCOVER_ONLY(val) val
1702 static PedDiskOps gpt_disk_ops =
1705 clobber: NULL_IF_DISCOVER_ONLY (gpt_clobber),
1707 duplicate: gpt_duplicate,
1710 write: NULL_IF_DISCOVER_ONLY (gpt_write),
1711 partition_new: gpt_partition_new,
1712 partition_duplicate: gpt_partition_duplicate,
1713 partition_destroy: gpt_partition_destroy,
1714 partition_set_system: gpt_partition_set_system,
1715 partition_set_flag: gpt_partition_set_flag,
1716 partition_get_flag: gpt_partition_get_flag,
1717 partition_is_flag_available: gpt_partition_is_flag_available,
1718 partition_set_name: gpt_partition_set_name,
1719 partition_get_name: gpt_partition_get_name,
1720 partition_align: gpt_partition_align,
1721 partition_enumerate: gpt_partition_enumerate,
1722 partition_check: gpt_partition_check,
1723 alloc_metadata: gpt_alloc_metadata,
1724 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1725 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1728 static PedDiskType gpt_disk_type =
1733 features: PED_DISK_TYPE_PARTITION_NAME
1737 ped_disk_gpt_init ()
1739 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1740 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1742 ped_disk_type_register (&gpt_disk_type);
1746 ped_disk_gpt_done ()
1748 ped_disk_type_unregister (&gpt_disk_type);