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>
47 # define _(String) gettext (String)
49 # define _(String) (String)
50 #endif /* ENABLE_NLS */
52 #define EFI_PMBR_OSTYPE_EFI 0xEE
53 #define MSDOS_MBR_SIGNATURE 0xaa55
55 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
57 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
58 * so some implementors got confused...
60 #define GPT_HEADER_REVISION_V1_02 0x00010200
61 #define GPT_HEADER_REVISION_V1_00 0x00010000
62 #define GPT_HEADER_REVISION_V0_99 0x00009900
64 typedef uint16_t efi_char16_t; /* UNICODE character */
65 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
66 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
67 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
68 typedef struct _PartitionRecord_t PartitionRecord_t;
69 typedef struct _LegacyMBR_t LegacyMBR_t;
70 typedef struct _GPTDiskData GPTDiskData;
75 uint16_t time_hi_and_version;
76 uint8_t clock_seq_hi_and_reserved;
77 uint8_t clock_seq_low;
79 } /* __attribute__ ((packed)) */ efi_guid_t;
80 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
81 * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
82 * data. It turns out we don't need it in this case, so it doesn't break
86 #define UNUSED_ENTRY_GUID \
87 ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
88 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
89 #define PARTITION_SYSTEM_GUID \
90 ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
91 PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
92 { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
93 #define PARTITION_BIOS_GRUB_GUID \
94 ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
95 PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
96 { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
97 #define LEGACY_MBR_PARTITION_GUID \
98 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
99 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
100 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
101 #define PARTITION_MSFT_RESERVED_GUID \
102 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
103 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
104 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
105 #define PARTITION_BASIC_DATA_GUID \
106 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
107 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
108 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
109 #define PARTITION_RAID_GUID \
110 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
111 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
112 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
113 #define PARTITION_SWAP_GUID \
114 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
115 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
116 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
117 #define PARTITION_LVM_GUID \
118 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
119 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
120 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
121 #define PARTITION_RESERVED_GUID \
122 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
123 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
124 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
125 #define PARTITION_HPSERVICE_GUID \
126 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
127 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
128 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
129 #define PARTITION_APPLE_HFS_GUID \
130 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
131 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
132 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
134 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
139 uint32_t HeaderCRC32;
142 uint64_t AlternateLBA;
143 uint64_t FirstUsableLBA;
144 uint64_t LastUsableLBA;
146 uint64_t PartitionEntryLBA;
147 uint32_t NumberOfPartitionEntries;
148 uint32_t SizeOfPartitionEntry;
149 uint32_t PartitionEntryArrayCRC32;
153 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
155 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
156 uint64_t RequiredToFunction:1;
157 uint64_t Reserved:47;
158 uint64_t GuidSpecific:16;
160 # warning "Using crippled partition entry type"
161 uint32_t RequiredToFunction:1;
162 uint32_t Reserved:32;
164 uint32_t GuidSpecific:16;
168 struct __attribute__ ((packed)) _GuidPartitionEntry_t
170 efi_guid_t PartitionTypeGuid;
171 efi_guid_t UniquePartitionGuid;
172 uint64_t StartingLBA;
174 GuidPartitionEntryAttributes_t Attributes;
175 efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
178 #define GPT_PMBR_LBA 0
179 #define GPT_PMBR_SECTORS 1
180 #define GPT_PRIMARY_HEADER_LBA 1
181 #define GPT_HEADER_SECTORS 1
182 #define GPT_PRIMARY_PART_TABLE_LBA 2
185 These values are only defaults. The actual on-disk structures
186 may define different sizes, so use those unless creating a new GPT disk!
189 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
191 /* Number of actual partition entries should be calculated as: */
192 #define GPT_DEFAULT_PARTITION_ENTRIES \
193 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
194 sizeof(GuidPartitionEntry_t))
196 struct __attribute__ ((packed)) _PartitionRecord_t
198 /* Not used by EFI firmware. Set to 0x80 to indicate that this
199 is the bootable legacy partition. */
200 uint8_t BootIndicator;
202 /* Start of partition in CHS address, not used by EFI firmware. */
205 /* Start of partition in CHS address, not used by EFI firmware. */
208 /* Start of partition in CHS address, not used by EFI firmware. */
211 /* OS type. A value of 0xEF defines an EFI system partition.
212 Other values are reserved for legacy operating systems, and
213 allocated independently of the EFI specification. */
216 /* End of partition in CHS address, not used by EFI firmware. */
219 /* End of partition in CHS address, not used by EFI firmware. */
222 /* End of partition in CHS address, not used by EFI firmware. */
225 /* Starting LBA address of the partition on the disk. Used by
226 EFI firmware to define the start of the partition. */
227 uint32_t StartingLBA;
229 /* Size of partition in LBA. Used by EFI firmware to determine
230 the size of the partition. */
234 /* Protected Master Boot Record & Legacy MBR share same structure */
235 /* Needs to be packed because the u16s force misalignment. */
236 struct __attribute__ ((packed)) _LegacyMBR_t
238 uint8_t BootCode[440];
239 uint32_t UniqueMBRSignature;
241 PartitionRecord_t PartitionRecord[4];
245 /* uses libparted's disk_specific field in PedDisk, to store our info */
246 struct __attribute__ ((packed)) _GPTDiskData
248 PedGeometry data_area;
253 /* uses libparted's disk_specific field in PedPartition, to store our info */
254 typedef struct _GPTPartitionData
268 static PedDiskType gpt_disk_type;
270 static inline uint32_t
271 pth_get_size (const PedDevice *dev)
273 return GPT_HEADER_SECTORS * dev->sector_size;
276 static inline uint32_t
277 pth_get_size_static (const PedDevice *dev)
279 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
282 static inline uint32_t
283 pth_get_size_rsv2 (const PedDevice *dev)
285 return pth_get_size (dev) - pth_get_size_static (dev);
288 static GuidPartitionTableHeader_t *
289 pth_new (const PedDevice *dev)
291 GuidPartitionTableHeader_t *pth =
292 ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
294 pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
299 static GuidPartitionTableHeader_t *
300 pth_new_zeroed (const PedDevice *dev)
302 GuidPartitionTableHeader_t *pth = pth_new (dev);
304 memset (pth, 0, pth_get_size_static (dev));
305 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
310 static GuidPartitionTableHeader_t *
311 pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
313 GuidPartitionTableHeader_t *pth = pth_new (dev);
315 PED_ASSERT (pth_raw != NULL, return 0);
317 memcpy (pth, pth_raw, pth_get_size_static (dev));
318 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
319 pth_get_size_rsv2 (dev));
325 pth_free (GuidPartitionTableHeader_t *pth)
327 PED_ASSERT (pth != NULL, return);
328 PED_ASSERT (pth->Reserved2 != NULL, return);
330 free (pth->Reserved2);
335 pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
337 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
338 int size_static = pth_get_size_static (dev);
340 PED_ASSERT (pth != NULL, return 0);
341 PED_ASSERT (pth->Reserved2 != NULL, return 0);
343 memcpy (pth_raw, pth, size_static);
344 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
350 * swap_uuid_and_efi_guid() - converts between uuid formats
351 * @uuid - uuid_t in either format (converts it to the other)
353 * There are two different representations for Globally Unique Identifiers
356 * The RFC specifies a UUID as a string of 16 bytes, essentially
357 * a big-endian array of char.
358 * Intel, in their EFI Specification, references the same RFC, but
359 * then defines a GUID as a structure of little-endian fields.
360 * Coincidentally, both structures have the same format when unparsed.
362 * When read from disk, EFI GUIDs are in struct of little endian format,
363 * and need to be converted to be treated as uuid_t in memory.
365 * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
370 swap_uuid_and_efi_guid (uuid_t uuid)
372 efi_guid_t *guid = (efi_guid_t *) uuid;
374 PED_ASSERT (uuid != NULL, return);
375 guid->time_low = PED_SWAP32 (guid->time_low);
376 guid->time_mid = PED_SWAP16 (guid->time_mid);
377 guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
380 /* returns the EFI-style CRC32 value for buf
381 * This function uses the crc32 function by Gary S. Brown,
382 * but seeds the function with ~0, and xor's with ~0 at the end.
384 static inline uint32_t
385 efi_crc32 (const void *buf, unsigned long len)
387 return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
390 static inline uint32_t
391 pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
393 uint8_t *pth_raw = pth_get_raw (dev, pth);
396 PED_ASSERT (dev != NULL, return 0);
397 PED_ASSERT (pth != NULL, return 0);
399 crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
407 guid_cmp (efi_guid_t left, efi_guid_t right)
409 return memcmp (&left, &right, sizeof (efi_guid_t));
412 /* checks if 'mbr' is a protective MBR partition table */
414 _pmbr_is_valid (const LegacyMBR_t *mbr)
418 PED_ASSERT (mbr != NULL, return 0);
420 if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
422 for (i = 0; i < 4; i++)
424 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
431 gpt_probe (const PedDevice *dev)
433 GuidPartitionTableHeader_t *gpt = NULL;
434 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
435 int gpt_sig_found = 0;
437 PED_ASSERT (dev != NULL, return 0);
439 if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
440 || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
442 gpt = pth_new_from_raw (dev, pth_raw);
443 if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
456 if (!ptt_read_sector (dev, 0, &label))
460 if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
462 int ex_status = ped_exception_throw
463 (PED_EXCEPTION_WARNING,
464 PED_EXCEPTION_YES_NO,
465 _("%s contains GPT signatures, indicating that it has "
466 "a GPT table. However, it does not have a valid "
467 "fake msdos partition table, as it should. Perhaps "
468 "it was corrupted -- possibly by a program that "
469 "doesn't understand GPT partition tables. Or "
470 "perhaps you deleted the GPT table, and are now "
471 "using an msdos partition table. Is this a GPT "
474 if (ex_status == PED_EXCEPTION_NO)
482 #ifndef DISCOVER_ONLY
483 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
485 gpt_clobber (PedDevice *dev)
487 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
488 GuidPartitionTableHeader_t *gpt;
490 PED_ASSERT (dev != NULL, return 0);
493 * TO DISCUSS: check whether checksum is correct?
494 * If not, we might get a wrong AlternateLBA field and destroy
495 * one sector of random data.
497 if (!ped_device_read (dev, pth_raw,
498 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
504 gpt = pth_new_from_raw (dev, pth_raw);
507 if (!ptt_clear_sectors (dev, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
508 goto error_free_with_gpt;
509 if (!ptt_clear_sectors (dev, GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
510 goto error_free_with_gpt;
511 if (!ptt_clear_sectors (dev, dev->length - GPT_HEADER_SECTORS,
513 goto error_free_with_gpt;
515 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1)
517 if (!ped_device_write (dev, gpt,
518 PED_LE64_TO_CPU (gpt->AlternateLBA),
531 #endif /* !DISCOVER_ONLY */
534 gpt_alloc (const PedDevice *dev)
537 GPTDiskData *gpt_disk_data;
538 PedSector data_start, data_end;
540 disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
543 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
544 if (!disk->disk_specific)
545 goto error_free_disk;
547 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
548 data_end = dev->length - 2
549 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
550 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
551 data_end - data_start + 1);
552 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
553 uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
554 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
564 gpt_duplicate (const PedDisk *disk)
567 GPTDiskData *new_disk_data;
568 GPTDiskData *old_disk_data;
570 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
574 old_disk_data = disk->disk_specific;
575 new_disk_data = new_disk->disk_specific;
577 ped_geometry_init (&new_disk_data->data_area, disk->dev,
578 old_disk_data->data_area.start,
579 old_disk_data->data_area.length);
580 new_disk_data->entry_count = old_disk_data->entry_count;
581 new_disk_data->uuid = old_disk_data->uuid;
586 gpt_free (PedDisk *disk)
588 ped_disk_delete_all (disk);
589 free (disk->disk_specific);
590 _ped_disk_free (disk);
594 _header_is_valid (const PedDevice *dev, GuidPartitionTableHeader_t *gpt,
597 uint32_t crc, origcrc;
599 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
602 * "While the GUID Partition Table Header's size may increase
603 * in the future it cannot span more than one block on the
604 * device." EFI Specification, version 1.10, 11.2.2.1
606 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
607 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
610 /* The SizeOfPartitionEntry must be a multiple of 8 and
611 no smaller than the size of the PartitionEntry structure.
612 We also require that be no larger than 1/16th of UINT32_MAX,
613 as an additional sanity check. */
614 uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
616 || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
619 if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
622 origcrc = gpt->HeaderCRC32;
623 gpt->HeaderCRC32 = 0;
624 crc = pth_crc32 (dev, gpt);
625 gpt->HeaderCRC32 = origcrc;
627 return crc == PED_LE32_TO_CPU (origcrc);
631 _read_header (const PedDevice *dev, GuidPartitionTableHeader_t **gpt,
634 uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
636 PED_ASSERT (dev != NULL, return 0);
638 if (!ped_device_read (dev, pth_raw, my_lba, GPT_HEADER_SECTORS))
644 *gpt = pth_new_from_raw (dev, pth_raw);
648 if (_header_is_valid (dev, *gpt, my_lba))
656 _parse_header (PedDisk *disk, GuidPartitionTableHeader_t *gpt,
659 GPTDiskData *gpt_disk_data = disk->disk_specific;
660 PedSector first_usable;
661 PedSector last_usable;
662 PedSector last_usable_if_grown, last_usable_min_default;
663 static int asked_already;
665 // PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0);
667 #ifndef DISCOVER_ONLY
668 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
670 if (ped_exception_throw
671 (PED_EXCEPTION_WARNING,
672 PED_EXCEPTION_IGNORE_CANCEL,
673 _("The format of the GPT partition table is version "
674 "%x, which is newer than what Parted can "
675 "recognise. Please tell us! bug-parted@gnu.org"),
676 PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
681 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
682 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
684 /* Need to check whether the volume has grown, the LastUsableLBA is
685 normally set to disk->dev->length - 2 - ptes_size (at least for parted
686 created volumes), where ptes_size is the number of entries *
687 size of each entry / sector size or 16k / sector size, whatever the greater.
688 If the volume has grown, offer the user the chance to use the new
689 space or continue with the current usable area. Only ask once per
690 parted invocation. */
693 = (disk->dev->length - 2 -
694 ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
695 (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
696 disk->dev->sector_size));
698 last_usable_min_default = disk->dev->length - 2 -
699 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
701 if (last_usable_if_grown > last_usable_min_default)
703 last_usable_if_grown = last_usable_min_default;
706 PED_ASSERT (last_usable > first_usable, return 0);
707 PED_ASSERT (last_usable <= disk->dev->length, return 0);
709 PED_ASSERT (last_usable_if_grown > first_usable, return 0);
710 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
712 if (!asked_already && last_usable < last_usable_if_grown)
715 PedExceptionOption q;
717 q = ped_exception_throw
718 (PED_EXCEPTION_WARNING,
719 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
720 _("Not all of the space available to %s appears "
721 "to be used, you can fix the GPT to use all of the "
722 "space (an extra %llu blocks) or continue with the "
723 "current setting? "), disk->dev->path,
724 (uint64_t) (last_usable_if_grown - last_usable));
726 if (q == PED_EXCEPTION_FIX)
728 last_usable = last_usable_if_grown;
731 else if (q != PED_EXCEPTION_UNHANDLED)
737 ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
738 first_usable, last_usable - first_usable + 1);
740 gpt_disk_data->entry_count
741 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
742 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
743 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
745 gpt_disk_data->uuid = gpt->DiskGUID;
750 static PedPartition *
751 _parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
754 GPTPartitionData *gpt_part_data;
757 part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
758 PED_LE64_TO_CPU (pte->StartingLBA),
759 PED_LE64_TO_CPU (pte->EndingLBA));
763 gpt_part_data = part->disk_specific;
764 gpt_part_data->type = pte->PartitionTypeGuid;
765 gpt_part_data->uuid = pte->UniquePartitionGuid;
766 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
767 gpt_part_data->name[i] =
768 (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
769 gpt_part_data->name[i] = 0;
771 gpt_part_data->lvm = gpt_part_data->raid
772 = gpt_part_data->boot = gpt_part_data->hp_service
773 = gpt_part_data->hidden = gpt_part_data->msftres
774 = gpt_part_data->bios_grub = 0;
776 if (pte->Attributes.RequiredToFunction & 0x1)
777 gpt_part_data->hidden = 1;
779 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
780 gpt_part_data->boot = 1;
781 else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
782 gpt_part_data->bios_grub = 1;
783 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
784 gpt_part_data->raid = 1;
785 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
786 gpt_part_data->lvm = 1;
787 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
788 gpt_part_data->hp_service = 1;
789 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
790 gpt_part_data->msftres = 1;
795 /************************************************************
796 * Intel is changing the EFI Spec. (after v1.02) to say that a
797 * disk is considered to have a GPT label only if the GPT
798 * structures are correct, and the MBR is actually a Protective
799 * MBR (has one 0xEE type partition).
800 * Problem occurs when a GPT-partitioned disk is then
801 * edited with a legacy (non-GPT-aware) application, such as
802 * fdisk (which doesn't generally erase the PGPT or AGPT).
803 * How should such a disk get handled? As a GPT disk (throwing
804 * away the fdisk changes), or as an MSDOS disk (throwing away
805 * the GPT information). Previously, I've taken the GPT-is-right,
806 * MBR is wrong, approach, to stay consistent with the EFI Spec.
807 * Intel disagrees, saying the disk should then be treated
808 * as having a msdos label, not a GPT label. If this is true,
809 * then what's the point of having an AGPT, since if the PGPT
810 * is screwed up, likely the PMBR is too, and the PMBR becomes
811 * a single point of failure.
812 * So, in the Linux kernel, I'm going to test for PMBR, and
813 * warn if it's not there, and treat the disk as MSDOS, with a note
814 * for users to use Parted to "fix up" their disk if they
815 * really want it to be considered GPT.
816 ************************************************************/
818 gpt_read (PedDisk *disk)
820 GPTDiskData *gpt_disk_data = disk->disk_specific;
821 GuidPartitionTableHeader_t *gpt;
824 #ifndef DISCOVER_ONLY
828 ped_disk_delete_all (disk);
830 /* motivation: let the user decide about the pmbr... during
831 ped_disk_probe(), they probably didn't get a choice... */
832 if (!gpt_probe (disk->dev))
835 if (_read_header (disk->dev, &gpt, 1))
837 /* There used to be a GPT partition table here, with an
838 alternate LBA that extended beyond the current
839 end-of-device. Treat it as a non-match. */
840 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
841 > disk->dev->length - 1)
844 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
845 < disk->dev->length - 1)
848 #ifndef DISCOVER_ONLY
849 switch (ped_exception_throw
850 (PED_EXCEPTION_ERROR,
852 PED_EXCEPTION_CANCEL |
853 PED_EXCEPTION_IGNORE,
854 _("The backup GPT table is not at the end of the disk, as it "
855 "should be. This might mean that another operating system "
856 "believes the disk is smaller. Fix, by moving the backup "
857 "to the end (and removing the old backup)?")))
859 case PED_EXCEPTION_CANCEL:
861 case PED_EXCEPTION_FIX:
863 char *zeros = ped_malloc (pth_get_size (disk->dev));
865 memset (zeros, 0, disk->dev->sector_size);
866 ped_device_write (disk->dev, zeros,
867 PED_LE64_TO_CPU (gpt->AlternateLBA), 1);
875 #endif /* !DISCOVER_ONLY */
879 { /* primary GPT *not* ok */
880 int alternate_ok = 0;
882 #ifndef DISCOVER_ONLY
886 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
887 < disk->dev->length - 1)
889 alternate_ok = _read_header (disk->dev, &gpt,
890 PED_LE64_TO_CPU (gpt->AlternateLBA));
894 alternate_ok = _read_header (disk->dev, &gpt,
895 disk->dev->length - 1);
900 if (ped_exception_throw
901 (PED_EXCEPTION_ERROR,
902 PED_EXCEPTION_OK_CANCEL,
903 _("The primary GPT table is corrupt, but the "
904 "backup appears OK, so that will be used."))
905 == PED_EXCEPTION_CANCEL)
910 ped_exception_throw (PED_EXCEPTION_ERROR,
911 PED_EXCEPTION_CANCEL,
912 _("Both the primary and backup GPT tables "
913 "are corrupt. Try making a fresh table, "
914 "and using Parted's rescue feature to "
915 "recover partitions."));
920 if (!_parse_header (disk, gpt, &write_back))
923 uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
924 size_t ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
925 size_t ptes_sectors = ped_div_round_up (ptes_bytes,
926 disk->dev->sector_size);
928 if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
930 ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
932 if (!ped_device_read (disk->dev, ptes,
933 PED_LE64_TO_CPU (gpt->PartitionEntryLBA),
935 goto error_free_ptes;
937 uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
938 if (ptes_crc != gpt->PartitionEntryArrayCRC32)
941 (PED_EXCEPTION_ERROR,
942 PED_EXCEPTION_CANCEL,
943 _("partition table array (FIXME:which?) CRC mismatch"));
944 goto error_free_ptes;
947 for (i = 0; i < gpt_disk_data->entry_count; i++)
949 GuidPartitionEntry_t *pte
950 = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
952 PedConstraint *constraint_exact;
954 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
957 part = _parse_part_entry (disk, pte);
959 goto error_delete_all;
961 part->fs_type = ped_file_system_probe (&part->geom);
964 constraint_exact = ped_constraint_exact (&part->geom);
965 if (!ped_disk_add_partition (disk, part, constraint_exact))
967 ped_partition_destroy (part);
968 goto error_delete_all;
970 ped_constraint_destroy (constraint_exact);
974 #ifndef DISCOVER_ONLY
976 ped_disk_commit_to_dev (disk);
983 ped_disk_delete_all (disk);
992 #ifndef DISCOVER_ONLY
993 /* Write the protective MBR (to keep DOS happy) */
995 _write_pmbr (PedDevice *dev)
997 /* The UEFI spec is not clear about what to do with the following
998 elements of the Protective MBR (pmbr): BootCode (0-440B),
999 UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1000 With this in mind, we try not to modify these elements. */
1002 if (!ptt_read_sector (dev, 0, &s0))
1004 LegacyMBR_t *pmbr = s0;
1006 /* Zero out the legacy partitions. */
1007 memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1009 pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1010 pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1011 pmbr->PartitionRecord[0].StartSector = 1;
1012 pmbr->PartitionRecord[0].EndHead = 0xFE;
1013 pmbr->PartitionRecord[0].EndSector = 0xFF;
1014 pmbr->PartitionRecord[0].EndTrack = 0xFF;
1015 pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1016 if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1017 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1019 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1021 int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1028 _generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1029 GuidPartitionTableHeader_t **gpt_p)
1031 GPTDiskData *gpt_disk_data = disk->disk_specific;
1032 GuidPartitionTableHeader_t *gpt;
1034 *gpt_p = pth_new_zeroed (disk->dev);
1038 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1039 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1042 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1043 gpt->HeaderCRC32 = 0;
1048 PedSector ptes_size = gpt_disk_data->entry_count
1049 * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1051 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1052 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1053 gpt->PartitionEntryLBA
1054 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1058 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1059 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1060 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1063 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1064 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1065 gpt->DiskGUID = gpt_disk_data->uuid;
1066 gpt->NumberOfPartitionEntries
1067 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1068 gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1069 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1070 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1074 _partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1076 GPTPartitionData *gpt_part_data = part->disk_specific;
1079 PED_ASSERT (gpt_part_data != NULL, return);
1081 pte->PartitionTypeGuid = gpt_part_data->type;
1082 pte->UniquePartitionGuid = gpt_part_data->uuid;
1083 pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1084 pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1085 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1087 if (gpt_part_data->hidden)
1088 pte->Attributes.RequiredToFunction = 1;
1090 for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1091 pte->PartitionName[i]
1092 = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1096 gpt_write (const PedDisk *disk)
1098 GPTDiskData *gpt_disk_data;
1099 GuidPartitionEntry_t *ptes;
1102 GuidPartitionTableHeader_t *gpt;
1106 PED_ASSERT (disk != NULL, goto error);
1107 PED_ASSERT (disk->dev != NULL, goto error);
1108 PED_ASSERT (disk->disk_specific != NULL, goto error);
1110 gpt_disk_data = disk->disk_specific;
1112 ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1113 ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1116 memset (ptes, 0, ptes_size);
1117 for (part = ped_disk_next_partition (disk, NULL); part;
1118 part = ped_disk_next_partition (disk, part))
1120 if (part->type != 0)
1122 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1125 ptes_crc = efi_crc32 (ptes, ptes_size);
1127 /* Write protective MBR */
1128 if (!_write_pmbr (disk->dev))
1129 goto error_free_ptes;
1131 /* Write PTH and PTEs */
1132 _generate_header (disk, 0, ptes_crc, &gpt);
1133 pth_raw = pth_get_raw (disk->dev, gpt);
1135 bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1138 goto error_free_ptes;
1139 if (!ped_device_write (disk->dev, ptes, 2,
1140 ptes_size / disk->dev->sector_size))
1141 goto error_free_ptes;
1143 /* Write Alternate PTH & PTEs */
1144 _generate_header (disk, 1, ptes_crc, &gpt);
1145 pth_raw = pth_get_raw (disk->dev, gpt);
1147 write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1150 goto error_free_ptes;
1151 if (!ped_device_write (disk->dev, ptes,
1152 disk->dev->length - 1 -
1153 ptes_size / disk->dev->sector_size,
1154 ptes_size / disk->dev->sector_size))
1155 goto error_free_ptes;
1158 return ped_device_sync (disk->dev);
1166 #endif /* !DISCOVER_ONLY */
1169 add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1172 PedConstraint *constraint_exact;
1173 PED_ASSERT (disk != NULL, return 0);
1175 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1176 start, start + length - 1);
1180 constraint_exact = ped_constraint_exact (&part->geom);
1181 if (!ped_disk_add_partition (disk, part, constraint_exact))
1182 goto error_destroy_constraint;
1183 ped_constraint_destroy (constraint_exact);
1186 error_destroy_constraint:
1187 ped_constraint_destroy (constraint_exact);
1188 ped_partition_destroy (part);
1193 static PedPartition *
1194 gpt_partition_new (const PedDisk *disk,
1195 PedPartitionType part_type,
1196 const PedFileSystemType *fs_type, PedSector start,
1200 GPTPartitionData *gpt_part_data;
1202 part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1209 gpt_part_data = part->disk_specific =
1210 ped_malloc (sizeof (GPTPartitionData));
1212 goto error_free_part;
1214 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1215 gpt_part_data->lvm = 0;
1216 gpt_part_data->raid = 0;
1217 gpt_part_data->boot = 0;
1218 gpt_part_data->bios_grub = 0;
1219 gpt_part_data->hp_service = 0;
1220 gpt_part_data->hidden = 0;
1221 gpt_part_data->msftres = 0;
1222 uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1223 swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1224 memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1228 _ped_partition_free (part);
1233 static PedPartition *
1234 gpt_partition_duplicate (const PedPartition *part)
1236 PedPartition *result;
1237 GPTPartitionData *part_data = part->disk_specific;
1238 GPTPartitionData *result_data;
1240 result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1241 part->geom.start, part->geom.end);
1244 result->num = part->num;
1246 if (result->type != 0)
1249 result_data = result->disk_specific =
1250 ped_malloc (sizeof (GPTPartitionData));
1252 goto error_free_part;
1254 result_data->type = part_data->type;
1255 result_data->uuid = part_data->uuid;
1256 strcpy (result_data->name, part_data->name);
1260 _ped_partition_free (result);
1266 gpt_partition_destroy (PedPartition *part)
1268 if (part->type == 0)
1270 PED_ASSERT (part->disk_specific != NULL, return);
1271 free (part->disk_specific);
1274 _ped_partition_free (part);
1278 gpt_partition_set_system (PedPartition *part,
1279 const PedFileSystemType *fs_type)
1281 GPTPartitionData *gpt_part_data = part->disk_specific;
1283 PED_ASSERT (gpt_part_data != NULL, return 0);
1285 part->fs_type = fs_type;
1287 if (gpt_part_data->lvm)
1289 gpt_part_data->type = PARTITION_LVM_GUID;
1292 if (gpt_part_data->raid)
1294 gpt_part_data->type = PARTITION_RAID_GUID;
1297 if (gpt_part_data->boot)
1299 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1302 if (gpt_part_data->bios_grub)
1304 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1307 if (gpt_part_data->hp_service)
1309 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1312 if (gpt_part_data->msftres)
1314 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1320 if (strncmp (fs_type->name, "fat", 3) == 0
1321 || strcmp (fs_type->name, "ntfs") == 0)
1323 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1326 if (strncmp (fs_type->name, "hfs", 3) == 0)
1328 gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1331 if (strstr (fs_type->name, "swap"))
1333 gpt_part_data->type = PARTITION_SWAP_GUID;
1338 gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1342 /* Allocate metadata partitions for the GPTH and PTES */
1344 gpt_alloc_metadata (PedDisk *disk)
1346 PedSector gptlength, pteslength = 0;
1347 GPTDiskData *gpt_disk_data;
1349 PED_ASSERT (disk != NULL, return 0);
1350 PED_ASSERT (disk->dev != NULL, return 0);
1351 PED_ASSERT (disk->disk_specific != NULL, return 0);
1352 gpt_disk_data = disk->disk_specific;
1354 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1355 disk->dev->sector_size);
1356 pteslength = ped_div_round_up (gpt_disk_data->entry_count
1357 * sizeof (GuidPartitionEntry_t),
1358 disk->dev->sector_size);
1360 /* metadata at the start of the disk includes the MBR */
1361 if (!add_metadata_part (disk, GPT_PMBR_LBA,
1362 GPT_PMBR_SECTORS + gptlength + pteslength))
1365 /* metadata at the end of the disk */
1366 if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1367 gptlength + pteslength))
1373 /* Does nothing, as the read/new/destroy functions maintain part->num */
1375 gpt_partition_enumerate (PedPartition *part)
1377 GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1380 /* never change the partition numbers */
1381 if (part->num != -1)
1384 for (i = 1; i <= gpt_disk_data->entry_count; i++)
1386 if (!ped_disk_get_partition (part->disk, i))
1393 PED_ASSERT (0, return 0);
1395 return 0; /* used if debug is disabled */
1399 gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1401 GPTPartitionData *gpt_part_data;
1402 PED_ASSERT (part != NULL, return 0);
1403 PED_ASSERT (part->disk_specific != NULL, return 0);
1404 gpt_part_data = part->disk_specific;
1408 case PED_PARTITION_BOOT:
1409 gpt_part_data->boot = state;
1412 = gpt_part_data->lvm
1413 = gpt_part_data->bios_grub
1414 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1415 return gpt_partition_set_system (part, part->fs_type);
1416 case PED_PARTITION_BIOS_GRUB:
1417 gpt_part_data->bios_grub = state;
1420 = gpt_part_data->lvm
1421 = gpt_part_data->boot
1422 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1423 return gpt_partition_set_system (part, part->fs_type);
1424 case PED_PARTITION_RAID:
1425 gpt_part_data->raid = state;
1428 = gpt_part_data->lvm
1429 = gpt_part_data->bios_grub
1430 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1431 return gpt_partition_set_system (part, part->fs_type);
1432 case PED_PARTITION_LVM:
1433 gpt_part_data->lvm = state;
1436 = gpt_part_data->raid
1437 = gpt_part_data->bios_grub
1438 = gpt_part_data->hp_service = gpt_part_data->msftres = 0;
1439 return gpt_partition_set_system (part, part->fs_type);
1440 case PED_PARTITION_HPSERVICE:
1441 gpt_part_data->hp_service = state;
1444 = gpt_part_data->raid
1445 = gpt_part_data->lvm
1446 = gpt_part_data->bios_grub = gpt_part_data->msftres = 0;
1447 return gpt_partition_set_system (part, part->fs_type);
1448 case PED_PARTITION_MSFT_RESERVED:
1449 gpt_part_data->msftres = state;
1452 = gpt_part_data->raid
1453 = gpt_part_data->lvm
1454 = gpt_part_data->bios_grub = gpt_part_data->hp_service = 0;
1455 return gpt_partition_set_system (part, part->fs_type);
1456 case PED_PARTITION_HIDDEN:
1457 gpt_part_data->hidden = state;
1459 case PED_PARTITION_SWAP:
1460 case PED_PARTITION_ROOT:
1461 case PED_PARTITION_LBA:
1469 gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1471 GPTPartitionData *gpt_part_data;
1472 PED_ASSERT (part->disk_specific != NULL, return 0);
1473 gpt_part_data = part->disk_specific;
1477 case PED_PARTITION_RAID:
1478 return gpt_part_data->raid;
1479 case PED_PARTITION_LVM:
1480 return gpt_part_data->lvm;
1481 case PED_PARTITION_BOOT:
1482 return gpt_part_data->boot;
1483 case PED_PARTITION_BIOS_GRUB:
1484 return gpt_part_data->bios_grub;
1485 case PED_PARTITION_HPSERVICE:
1486 return gpt_part_data->hp_service;
1487 case PED_PARTITION_MSFT_RESERVED:
1488 return gpt_part_data->msftres;
1489 case PED_PARTITION_HIDDEN:
1490 return gpt_part_data->hidden;
1491 case PED_PARTITION_SWAP:
1492 case PED_PARTITION_LBA:
1493 case PED_PARTITION_ROOT:
1501 gpt_partition_is_flag_available (const PedPartition *part,
1502 PedPartitionFlag flag)
1506 case PED_PARTITION_RAID:
1507 case PED_PARTITION_LVM:
1508 case PED_PARTITION_BOOT:
1509 case PED_PARTITION_BIOS_GRUB:
1510 case PED_PARTITION_HPSERVICE:
1511 case PED_PARTITION_MSFT_RESERVED:
1512 case PED_PARTITION_HIDDEN:
1514 case PED_PARTITION_SWAP:
1515 case PED_PARTITION_ROOT:
1516 case PED_PARTITION_LBA:
1524 gpt_partition_set_name (PedPartition *part, const char *name)
1526 GPTPartitionData *gpt_part_data = part->disk_specific;
1528 strncpy (gpt_part_data->name, name, 36);
1529 gpt_part_data->name[36] = 0;
1533 gpt_partition_get_name (const PedPartition *part)
1535 GPTPartitionData *gpt_part_data = part->disk_specific;
1536 return gpt_part_data->name;
1540 gpt_get_max_primary_partition_count (const PedDisk *disk)
1542 const GPTDiskData *gpt_disk_data = disk->disk_specific;
1543 return gpt_disk_data->entry_count;
1547 * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1548 * According to the specs the first LBA (LBA0) is not relevant (it exists
1549 * to maintain compatibility). on the second LBA(LBA1) gpt places the
1550 * header. The header is as big as the block size. After the header we
1551 * find the Entry array. Each element of said array, describes each
1552 * partition. One can have as much elements as can fit between the end of
1553 * the second LBA (where the header ends) and the FirstUsableLBA.
1554 * FirstUsableLBA is the first logical block that is used for contents
1555 * and is defined in header.
1557 * /---------------------------------------------------\
1558 * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1560 * \---------------------------------------------------/
1562 * /----------/ \----------\
1563 * /-----------------------------------------\
1564 * | E1 | E2 | E3 |...............| EN |
1565 * \-----------------------------------------/
1567 * The number of possible partitions or supported partitions is:
1568 * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1569 * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1572 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1574 GuidPartitionTableHeader_t *pth = NULL;
1575 uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1577 if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1578 || ped_device_read (disk->dev, pth_raw,
1579 disk->dev->length, GPT_HEADER_SECTORS))
1580 pth = pth_new_from_raw (disk->dev, pth_raw);
1586 *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1587 / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1592 static PedConstraint *
1593 _non_metadata_constraint (const PedDisk *disk)
1595 GPTDiskData *gpt_disk_data = disk->disk_specific;
1597 return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1601 gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1603 PED_ASSERT (part != NULL, return 0);
1605 if (_ped_partition_attempt_align (part, constraint,
1606 _non_metadata_constraint (part->disk)))
1609 #ifndef DISCOVER_ONLY
1610 ped_exception_throw (PED_EXCEPTION_ERROR,
1611 PED_EXCEPTION_CANCEL,
1612 _("Unable to satisfy all constraints on the partition."));
1618 gpt_partition_check (const PedPartition *part)
1623 #ifdef DISCOVER_ONLY
1624 # define NULL_IF_DISCOVER_ONLY(val) NULL
1626 # define NULL_IF_DISCOVER_ONLY(val) val
1629 static PedDiskOps gpt_disk_ops =
1632 clobber: NULL_IF_DISCOVER_ONLY (gpt_clobber),
1634 duplicate: gpt_duplicate,
1637 write: NULL_IF_DISCOVER_ONLY (gpt_write),
1638 partition_new: gpt_partition_new,
1639 partition_duplicate: gpt_partition_duplicate,
1640 partition_destroy: gpt_partition_destroy,
1641 partition_set_system: gpt_partition_set_system,
1642 partition_set_flag: gpt_partition_set_flag,
1643 partition_get_flag: gpt_partition_get_flag,
1644 partition_is_flag_available: gpt_partition_is_flag_available,
1645 partition_set_name: gpt_partition_set_name,
1646 partition_get_name: gpt_partition_get_name,
1647 partition_align: gpt_partition_align,
1648 partition_enumerate: gpt_partition_enumerate,
1649 partition_check: gpt_partition_check,
1650 alloc_metadata: gpt_alloc_metadata,
1651 get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1652 get_max_supported_partition_count: gpt_get_max_supported_partition_count
1655 static PedDiskType gpt_disk_type =
1660 features: PED_DISK_TYPE_PARTITION_NAME
1664 ped_disk_gpt_init ()
1666 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1667 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1669 ped_disk_type_register (&gpt_disk_type);
1673 ped_disk_gpt_done ()
1675 ped_disk_type_unregister (&gpt_disk_type);