1 /* 2 libparted - a library for manipulating disk partitions 3 4 original version by Matt Domsch <Matt_Domsch@dell.com> 5 Disclaimed into the Public Domain 6 7 Portions Copyright (C) 2001, 2002, 2003, 2005, 2006, 2007 8 Free Software Foundation, Inc. 9 10 EFI GUID Partition Table handling 11 Per Intel EFI Specification v1.02 12 http://developer.intel.com/technology/efi/efi.htm 13 14 This program is free software; you can redistribute it and/or modify 15 it under the terms of the GNU General Public License as published by 16 the Free Software Foundation; either version 3 of the License, or 17 (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, 20 but WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 GNU General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program. If not, see <http://www.gnu.org/licenses/>. 26 */ 27 28 #include <config.h> 29 30 #include <parted/parted.h> 31 #include <parted/debug.h> 32 #include <parted/endian.h> 33 #include <parted/crc32.h> 34 #include <inttypes.h> 35 #include <stdio.h> 36 #include <sys/types.h> 37 #include <sys/ioctl.h> 38 #include <fcntl.h> 39 #include <unistd.h> 40 #include <uuid/uuid.h> 41 42 #if ENABLE_NLS 43 # include <libintl.h> 44 # define _(String) gettext (String) 45 #else 46 # define _(String) (String) 47 #endif /* ENABLE_NLS */ 48 49 #define EFI_PMBR_OSTYPE_EFI 0xEE 50 #define MSDOS_MBR_SIGNATURE 0xaa55 51 52 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL 53 54 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02", 55 * so some implementors got confused... 56 */ 57 #define GPT_HEADER_REVISION_V1_02 0x00010200 58 #define GPT_HEADER_REVISION_V1_00 0x00010000 59 #define GPT_HEADER_REVISION_V0_99 0x00009900 60 61 #ifdef __sun 62 #define __attribute__(X) /*nothing*/ 63 #endif /* __sun */ 64 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; 72 typedef struct { 73 uint32_t time_low; 74 uint16_t time_mid; 75 uint16_t time_hi_and_version; 76 uint8_t clock_seq_hi_and_reserved; 77 uint8_t clock_seq_low; 78 uint8_t node[6]; 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 83 * anything :) 84 */ 85 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 LEGACY_MBR_PARTITION_GUID \ 94 ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \ 95 PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \ 96 { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }}) 97 #define PARTITION_MSFT_RESERVED_GUID \ 98 ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \ 99 PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \ 100 { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }}) 101 #define PARTITION_BASIC_DATA_GUID \ 102 ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \ 103 PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \ 104 { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }}) 105 #define PARTITION_RAID_GUID \ 106 ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \ 107 PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \ 108 { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }}) 109 #define PARTITION_SWAP_GUID \ 110 ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \ 111 PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \ 112 { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }}) 113 #define PARTITION_LVM_GUID \ 114 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \ 115 PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \ 116 { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }}) 117 #define PARTITION_RESERVED_GUID \ 118 ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \ 119 PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \ 120 { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }}) 121 #define PARTITION_HPSERVICE_GUID \ 122 ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \ 123 PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \ 124 { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }}) 125 #define PARTITION_APPLE_HFS_GUID \ 126 ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \ 127 PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \ 128 { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }}) 129 130 #ifdef __sun 131 #pragma pack(1) 132 #endif 133 struct __attribute__ ((packed)) _GuidPartitionTableHeader_t { 134 uint64_t Signature; 135 uint32_t Revision; 136 uint32_t HeaderSize; 137 uint32_t HeaderCRC32; 138 uint32_t Reserved1; 139 uint64_t MyLBA; 140 uint64_t AlternateLBA; 141 uint64_t FirstUsableLBA; 142 uint64_t LastUsableLBA; 143 efi_guid_t DiskGUID; 144 uint64_t PartitionEntryLBA; 145 uint32_t NumberOfPartitionEntries; 146 uint32_t SizeOfPartitionEntry; 147 uint32_t PartitionEntryArrayCRC32; 148 uint8_t* Reserved2; 149 }; 150 151 struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t { 152 #if defined(__GNUC__) || defined(__sun) /* XXX narrow this down to !TinyCC */ 153 uint64_t RequiredToFunction:1; 154 uint64_t Reserved:47; 155 uint64_t GuidSpecific:16; 156 #else 157 uint32_t RequiredToFunction:1; 158 uint32_t Reserved:32; 159 uint32_t LOST:5; 160 uint32_t GuidSpecific:16; 161 #endif 162 }; 163 164 struct __attribute__ ((packed)) _GuidPartitionEntry_t { 165 efi_guid_t PartitionTypeGuid; 166 efi_guid_t UniquePartitionGuid; 167 uint64_t StartingLBA; 168 uint64_t EndingLBA; 169 GuidPartitionEntryAttributes_t Attributes; 170 efi_char16_t PartitionName[72 / sizeof(efi_char16_t)]; 171 }; 172 #ifdef __sun 173 #pragma pack() 174 #endif 175 176 #define GPT_PMBR_LBA 0 177 #define GPT_PMBR_SECTORS 1 178 #define GPT_PRIMARY_HEADER_LBA 1 179 #define GPT_HEADER_SECTORS 1 180 #define GPT_PRIMARY_PART_TABLE_LBA 2 181 182 /* 183 These values are only defaults. The actual on-disk structures 184 may define different sizes, so use those unless creating a new GPT disk! 185 */ 186 187 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384 188 189 /* Number of actual partition entries should be calculated as: */ 190 #define GPT_DEFAULT_PARTITION_ENTRIES \ 191 (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \ 192 sizeof(GuidPartitionEntry_t)) 193 194 195 #ifdef __sun 196 #pragma pack(1) 197 #endif 198 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; 202 203 /* Start of partition in CHS address, not used by EFI firmware. */ 204 uint8_t StartHead; 205 206 /* Start of partition in CHS address, not used by EFI firmware. */ 207 uint8_t StartSector; 208 209 /* Start of partition in CHS address, not used by EFI firmware. */ 210 uint8_t StartTrack; 211 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. */ 215 uint8_t OSType; 216 217 /* End of partition in CHS address, not used by EFI firmware. */ 218 uint8_t EndHead; 219 220 /* End of partition in CHS address, not used by EFI firmware. */ 221 uint8_t EndSector; 222 223 /* End of partition in CHS address, not used by EFI firmware. */ 224 uint8_t EndTrack; 225 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; 229 230 /* Size of partition in LBA. Used by EFI firmware to determine 231 the size of the partition. */ 232 uint32_t SizeInLBA; 233 }; 234 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 { 238 uint8_t BootCode[440]; 239 uint32_t UniqueMBRSignature; 240 uint16_t Unknown; 241 PartitionRecord_t PartitionRecord[4]; 242 uint16_t Signature; 243 }; 244 245 /* uses libparted's disk_specific field in PedDisk, to store our info */ 246 struct __attribute__ ((packed)) _GPTDiskData { 247 PedGeometry data_area; 248 int entry_count; 249 efi_guid_t uuid; 250 }; 251 #ifdef __sun 252 #pragma pack() 253 #endif 254 255 /* uses libparted's disk_specific field in PedPartition, to store our info */ 256 typedef struct _GPTPartitionData { 257 efi_guid_t type; 258 efi_guid_t uuid; 259 char name[37]; 260 int lvm; 261 int raid; 262 int boot; 263 int hp_service; 264 int hidden; 265 int msftres; 266 } GPTPartitionData; 267 268 static PedDiskType gpt_disk_type; 269 270 271 static inline uint32_t 272 pth_get_size (const PedDevice* dev) 273 { 274 return GPT_HEADER_SECTORS * dev->sector_size; 275 } 276 277 278 static inline uint32_t 279 pth_get_size_static (const PedDevice* dev) 280 { 281 return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*); 282 } 283 284 285 static inline uint32_t 286 pth_get_size_rsv2 (const PedDevice* dev) 287 { 288 return pth_get_size(dev) - pth_get_size_static(dev); 289 } 290 291 292 static GuidPartitionTableHeader_t* 293 pth_new (const PedDevice* dev) 294 { 295 GuidPartitionTableHeader_t* pth = ped_malloc ( 296 sizeof (GuidPartitionTableHeader_t) 297 + sizeof (uint8_t)); 298 299 pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) ); 300 301 return pth; 302 } 303 304 305 static GuidPartitionTableHeader_t* 306 pth_new_zeroed (const PedDevice* dev) 307 { 308 GuidPartitionTableHeader_t* pth = pth_new (dev); 309 310 memset (pth, 0, pth_get_size_static (dev)); 311 memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev)); 312 313 return (pth); 314 } 315 316 317 static GuidPartitionTableHeader_t* 318 pth_new_from_raw (const PedDevice* dev, const uint8_t* pth_raw) 319 { 320 GuidPartitionTableHeader_t* pth = pth_new (dev); 321 322 PED_ASSERT (pth_raw != NULL, return 0); 323 324 memcpy (pth, pth_raw, pth_get_size_static (dev)); 325 memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev), 326 pth_get_size_rsv2 (dev)); 327 328 return pth; 329 } 330 331 static void 332 pth_free (GuidPartitionTableHeader_t* pth) 333 { 334 PED_ASSERT (pth != NULL, return); 335 PED_ASSERT (pth->Reserved2 != NULL, return); 336 337 ped_free (pth->Reserved2); 338 ped_free (pth); 339 } 340 341 static uint8_t* 342 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth) 343 { 344 uint8_t* pth_raw = ped_malloc (pth_get_size (dev)); 345 int size_static = pth_get_size_static (dev); 346 347 PED_ASSERT (pth != NULL, return 0); 348 PED_ASSERT (pth->Reserved2 != NULL, return 0); 349 350 memcpy (pth_raw, pth, size_static); 351 memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev)); 352 353 return pth_raw; 354 } 355 356 357 /** 358 * swap_uuid_and_efi_guid() - converts between uuid formats 359 * @uuid - uuid_t in either format (converts it to the other) 360 * 361 * There are two different representations for Globally Unique Identifiers 362 * (GUIDs or UUIDs). 363 * 364 * The RFC specifies a UUID as a string of 16 bytes, essentially 365 * a big-endian array of char. 366 * Intel, in their EFI Specification, references the same RFC, but 367 * then defines a GUID as a structure of little-endian fields. 368 * Coincidentally, both structures have the same format when unparsed. 369 * 370 * When read from disk, EFI GUIDs are in struct of little endian format, 371 * and need to be converted to be treated as uuid_t in memory. 372 * 373 * When writing to disk, uuid_ts need to be converted into EFI GUIDs. 374 * 375 * Blame Intel. 376 */ 377 static void 378 swap_uuid_and_efi_guid(uuid_t uuid) 379 { 380 efi_guid_t *guid = (efi_guid_t *)uuid; 381 382 PED_ASSERT(uuid != NULL, return); 383 guid->time_low = PED_SWAP32(guid->time_low); 384 guid->time_mid = PED_SWAP16(guid->time_mid); 385 guid->time_hi_and_version = PED_SWAP16(guid->time_hi_and_version); 386 } 387 388 /* returns the EFI-style CRC32 value for buf 389 * This function uses the crc32 function by Gary S. Brown, 390 * but seeds the function with ~0, and xor's with ~0 at the end. 391 */ 392 static inline uint32_t 393 efi_crc32(const void *buf, unsigned long len) 394 { 395 return (__efi_crc32(buf, len, ~0L) ^ ~0L); 396 } 397 398 static inline uint32_t 399 pth_crc32(const PedDevice* dev, const GuidPartitionTableHeader_t* pth) 400 { 401 uint8_t* pth_raw = pth_get_raw (dev, pth); 402 uint32_t crc32 = 0; 403 404 PED_ASSERT (dev != NULL, return 0); 405 PED_ASSERT (pth != NULL, return 0); 406 407 crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize)); 408 409 ped_free (pth_raw); 410 411 return crc32; 412 } 413 414 static inline int 415 guid_cmp (efi_guid_t left, efi_guid_t right) 416 { 417 return memcmp(&left, &right, sizeof(efi_guid_t)); 418 } 419 420 /* checks if 'mbr' is a protective MBR partition table */ 421 static inline int 422 _pmbr_is_valid (const LegacyMBR_t* mbr) 423 { 424 int i; 425 426 PED_ASSERT(mbr != NULL, return 0); 427 428 if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE)) 429 return 0; 430 for (i = 0; i < 4; i++) { 431 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI) 432 return 1; 433 } 434 return 0; 435 } 436 437 static int 438 gpt_probe (const PedDevice * dev) 439 { 440 GuidPartitionTableHeader_t* gpt = NULL; 441 uint8_t* pth_raw = ped_malloc (pth_get_size (dev)); 442 LegacyMBR_t legacy_mbr; 443 int gpt_sig_found = 0; 444 445 PED_ASSERT (dev != NULL, return 0); 446 PED_ASSERT (pth_raw != NULL, return 0); 447 448 if (ped_device_read(dev, pth_raw, 1, GPT_HEADER_SECTORS) 449 || 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)) 452 gpt_sig_found = 1; 453 } 454 455 ped_free (pth_raw); 456 457 if (gpt) 458 pth_free (gpt); 459 460 461 if (!gpt_sig_found) 462 return 0; 463 464 if (ped_device_read(dev, &legacy_mbr, 0, GPT_HEADER_SECTORS)) { 465 if (!_pmbr_is_valid (&legacy_mbr)) { 466 int ex_status = ped_exception_throw ( 467 PED_EXCEPTION_WARNING, 468 PED_EXCEPTION_YES_NO, 469 _("%s contains GPT signatures, indicating that it has " 470 "a GPT table. However, it does not have a valid " 471 "fake msdos partition table, as it should. Perhaps " 472 "it was corrupted -- possibly by a program that " 473 "doesn't understand GPT partition tables. Or " 474 "perhaps you deleted the GPT table, and are now " 475 "using an msdos partition table. Is this a GPT " 476 "partition table?"), 477 dev->path); 478 if (ex_status == PED_EXCEPTION_NO) 479 return 0; 480 } 481 } 482 483 return 1; 484 } 485 486 #ifndef DISCOVER_ONLY 487 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */ 488 static int 489 gpt_clobber(PedDevice * dev) 490 { 491 LegacyMBR_t pmbr; 492 uint8_t* zeroed_pth_raw = ped_malloc (pth_get_size (dev)); 493 uint8_t* pth_raw = ped_malloc (pth_get_size (dev)); 494 GuidPartitionTableHeader_t* gpt; 495 496 PED_ASSERT (dev != NULL, return 0); 497 498 memset(&pmbr, 0, sizeof(pmbr)); 499 memset(zeroed_pth_raw, 0, pth_get_size (dev)); 500 501 /* 502 * TO DISCUSS: check whether checksum is correct? 503 * If not, we might get a wrong AlternateLBA field and destroy 504 * one sector of random data. 505 */ 506 if (!ped_device_read(dev, pth_raw, 507 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS)) 508 goto error_free; 509 510 gpt = pth_new_from_raw (dev, pth_raw); 511 512 if (!ped_device_write(dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS)) 513 goto error_free_with_gpt; 514 if (!ped_device_write(dev, &zeroed_pth_raw, 515 GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS)) 516 goto error_free_with_gpt; 517 if (!ped_device_write(dev, &zeroed_pth_raw, dev->length - GPT_HEADER_SECTORS, 518 GPT_HEADER_SECTORS)) 519 goto error_free_with_gpt; 520 521 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1) { 522 if (!ped_device_write(dev, gpt, 523 PED_LE64_TO_CPU (gpt->AlternateLBA), 524 GPT_HEADER_SECTORS)) 525 return 0; 526 } 527 528 pth_free (gpt); 529 530 return 1; 531 532 error_free_with_gpt: 533 pth_free (gpt); 534 error_free: 535 ped_free (pth_raw); 536 ped_free (zeroed_pth_raw); 537 return 0; 538 } 539 #endif /* !DISCOVER_ONLY */ 540 541 static PedDisk * 542 gpt_alloc (const PedDevice * dev) 543 { 544 PedDisk* disk; 545 GPTDiskData *gpt_disk_data; 546 PedSector data_start, data_end; 547 548 disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_disk_type); 549 if (!disk) 550 goto error; 551 disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData)); 552 if (!disk->disk_specific) 553 goto error_free_disk; 554 555 data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size; 556 data_end = dev->length - 2 557 - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size; 558 ped_geometry_init (&gpt_disk_data->data_area, dev, data_start, 559 data_end - data_start + 1); 560 gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES; 561 uuid_generate ((unsigned char*) &gpt_disk_data->uuid); 562 swap_uuid_and_efi_guid((unsigned char*)(&gpt_disk_data->uuid)); 563 return disk; 564 565 error_free_disk: 566 ped_free (disk); 567 error: 568 return NULL; 569 } 570 571 static PedDisk* 572 gpt_duplicate (const PedDisk* disk) 573 { 574 PedDisk* new_disk; 575 GPTDiskData* new_disk_data; 576 GPTDiskData* old_disk_data; 577 578 new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type); 579 if (!new_disk) 580 return NULL; 581 582 old_disk_data = disk->disk_specific; 583 new_disk_data = new_disk->disk_specific; 584 585 ped_geometry_init (&new_disk_data->data_area, disk->dev, 586 old_disk_data->data_area.start, 587 old_disk_data->data_area.length); 588 new_disk_data->entry_count = old_disk_data->entry_count; 589 new_disk_data->uuid = old_disk_data->uuid; 590 return new_disk; 591 } 592 593 static void 594 gpt_free(PedDisk * disk) 595 { 596 ped_disk_delete_all (disk); 597 ped_free (disk->disk_specific); 598 _ped_disk_free (disk); 599 } 600 601 static int 602 _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt) 603 { 604 uint32_t crc, origcrc; 605 606 if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE) 607 return 0; 608 /* 609 * "While the GUID Partition Table Header's size may increase 610 * in the future it cannot span more than one block on the 611 * device." EFI Specification, version 1.10, 11.2.2.1 612 */ 613 if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev) 614 || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size) 615 return 0; 616 617 origcrc = gpt->HeaderCRC32; 618 gpt->HeaderCRC32 = 0; 619 crc = pth_crc32 (dev, gpt); 620 gpt->HeaderCRC32 = origcrc; 621 622 return crc == PED_LE32_TO_CPU (origcrc); 623 } 624 625 static int 626 _read_header (const PedDevice* dev, GuidPartitionTableHeader_t** gpt, 627 PedSector where) 628 { 629 uint8_t* pth_raw = ped_malloc (pth_get_size (dev)); 630 631 PED_ASSERT (dev != NULL, return 0); 632 633 if (!ped_device_read (dev, pth_raw, where, GPT_HEADER_SECTORS)) { 634 ped_free (pth_raw); 635 return 0; 636 } 637 638 *gpt = pth_new_from_raw (dev, pth_raw); 639 640 ped_free (pth_raw); 641 642 if (_header_is_valid (dev, *gpt)) 643 return 1; 644 645 pth_free (*gpt); 646 return 0; 647 } 648 649 static int 650 _parse_header (PedDisk* disk, GuidPartitionTableHeader_t* gpt, 651 int *update_needed) 652 { 653 GPTDiskData* gpt_disk_data = disk->disk_specific; 654 PedSector first_usable; 655 PedSector last_usable; 656 PedSector last_usable_if_grown, last_usable_min_default; 657 static int asked_already; 658 659 PED_ASSERT (_header_is_valid (disk->dev, gpt), return 0); 660 661 #ifndef DISCOVER_ONLY 662 if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02) { 663 if (ped_exception_throw ( 664 PED_EXCEPTION_WARNING, 665 PED_EXCEPTION_IGNORE_CANCEL, 666 _("The format of the GPT partition table is version " 667 "%x, which is newer than what Parted can " 668 "recognise. Please tell us! bug-parted@gnu.org"), 669 PED_LE32_TO_CPU (gpt->Revision)) 670 != PED_EXCEPTION_IGNORE) 671 return 0; 672 } 673 #endif 674 675 first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA); 676 last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA); 677 678 679 /* 680 Need to check whether the volume has grown, the LastUsableLBA is 681 normally set to disk->dev->length - 2 - ptes_size (at least for parted 682 created volumes), where ptes_size is the number of entries * 683 size of each entry / sector size or 16k / sector size, whatever the greater. 684 If the volume has grown, offer the user the chance to use the new 685 space or continue with the current usable area. Only ask once per 686 parted invocation. 687 */ 688 689 last_usable_if_grown 690 = PED_CPU_TO_LE64 (disk->dev->length - 2 - 691 ((PedSector)(PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries)) * 692 (PedSector)(PED_LE32_TO_CPU(gpt->SizeOfPartitionEntry)) / 693 disk->dev->sector_size)); 694 695 last_usable_min_default = disk->dev->length - 2 - 696 GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size; 697 698 if ( last_usable_if_grown > last_usable_min_default ) { 699 700 last_usable_if_grown = last_usable_min_default; 701 } 702 703 704 PED_ASSERT (last_usable > first_usable, return 0); 705 PED_ASSERT (last_usable <= disk->dev->length, return 0); 706 707 PED_ASSERT (last_usable_if_grown > first_usable, return 0); 708 PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0); 709 710 if ( !asked_already && last_usable < last_usable_if_grown ) { 711 712 PedExceptionOption q; 713 714 q = ped_exception_throw (PED_EXCEPTION_WARNING, 715 PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE, 716 _("Not all of the space available to %s appears " 717 "to be used, you can fix the GPT to use all of the " 718 "space (an extra %llu blocks) or continue with the " 719 "current setting? "), disk->dev->path, 720 (uint64_t)(last_usable_if_grown - last_usable)); 721 722 723 if (q == PED_EXCEPTION_FIX) { 724 725 last_usable = last_usable_if_grown; 726 *update_needed = 1; 727 728 } 729 else if (q != PED_EXCEPTION_UNHANDLED ) { 730 731 asked_already = 1; 732 } 733 } 734 735 ped_geometry_init (&gpt_disk_data->data_area, disk->dev, 736 first_usable, last_usable - first_usable + 1); 737 738 739 gpt_disk_data->entry_count 740 = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries); 741 PED_ASSERT (gpt_disk_data->entry_count > 0, return 0); 742 PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0); 743 744 gpt_disk_data->uuid = gpt->DiskGUID; 745 746 return 1; 747 } 748 749 static PedPartition* 750 _parse_part_entry (PedDisk* disk, GuidPartitionEntry_t* pte) 751 { 752 PedPartition* part; 753 GPTPartitionData* gpt_part_data; 754 unsigned int i; 755 756 part = ped_partition_new (disk, 0, NULL, 757 PED_LE64_TO_CPU(pte->StartingLBA), 758 PED_LE64_TO_CPU(pte->EndingLBA)); 759 if (!part) 760 return NULL; 761 762 gpt_part_data = part->disk_specific; 763 gpt_part_data->type = pte->PartitionTypeGuid; 764 gpt_part_data->uuid = pte->UniquePartitionGuid; 765 for (i = 0; i < 72 / sizeof (efi_char16_t); i++) 766 gpt_part_data->name[i] = (efi_char16_t) PED_LE16_TO_CPU( 767 (uint16_t) pte->PartitionName[i]); 768 gpt_part_data->name[i] = 0; 769 770 gpt_part_data->lvm = gpt_part_data->raid 771 = gpt_part_data->boot = gpt_part_data->hp_service 772 = gpt_part_data->hidden = gpt_part_data->msftres = 0; 773 774 if (pte->Attributes.RequiredToFunction & 0x1) 775 gpt_part_data->hidden = 1; 776 777 if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID)) 778 gpt_part_data->boot = 1; 779 else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID)) 780 gpt_part_data->raid = 1; 781 else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID)) 782 gpt_part_data->lvm = 1; 783 else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID)) 784 gpt_part_data->hp_service = 1; 785 else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID)) 786 gpt_part_data->msftres = 1; 787 788 return part; 789 } 790 791 /************************************************************ 792 * Intel is changing the EFI Spec. (after v1.02) to say that a 793 * disk is considered to have a GPT label only if the GPT 794 * structures are correct, and the MBR is actually a Protective 795 * MBR (has one 0xEE type partition). 796 * Problem occurs when a GPT-partitioned disk is then 797 * edited with a legacy (non-GPT-aware) application, such as 798 * fdisk (which doesn't generally erase the PGPT or AGPT). 799 * How should such a disk get handled? As a GPT disk (throwing 800 * away the fdisk changes), or as an MSDOS disk (throwing away 801 * the GPT information). Previously, I've taken the GPT-is-right, 802 * MBR is wrong, approach, to stay consistent with the EFI Spec. 803 * Intel disagrees, saying the disk should then be treated 804 * as having a msdos label, not a GPT label. If this is true, 805 * then what's the point of having an AGPT, since if the PGPT 806 * is screwed up, likely the PMBR is too, and the PMBR becomes 807 * a single point of failure. 808 * So, in the Linux kernel, I'm going to test for PMBR, and 809 * warn if it's not there, and treat the disk as MSDOS, with a note 810 * for users to use Parted to "fix up" their disk if they 811 * really want it to be considered GPT. 812 ************************************************************/ 813 static int 814 gpt_read (PedDisk * disk) 815 { 816 GPTDiskData *gpt_disk_data = disk->disk_specific; 817 GuidPartitionTableHeader_t* gpt; 818 GuidPartitionEntry_t* ptes; 819 int ptes_size; 820 int i; 821 #ifndef DISCOVER_ONLY 822 int write_back = 0; 823 #endif 824 825 ped_disk_delete_all (disk); 826 827 /* 828 * motivation: let the user decide about the pmbr... during 829 * ped_disk_probe(), they probably didn't get a choice... 830 */ 831 if (!gpt_probe (disk->dev)) 832 goto error; 833 834 if (_read_header (disk->dev, &gpt, 1)) { 835 PED_ASSERT ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) 836 <= disk->dev->length - 1, goto error_free_gpt); 837 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) 838 < disk->dev->length - 1) { 839 char* zeros = ped_malloc (pth_get_size (disk->dev)); 840 841 #ifndef DISCOVER_ONLY 842 if (ped_exception_throw ( 843 PED_EXCEPTION_ERROR, 844 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL, 845 _("The backup GPT table is not at the end of the disk, as it " 846 "should be. This might mean that another operating system " 847 "believes the disk is smaller. Fix, by moving the backup " 848 "to the end (and removing the old backup)?")) 849 == PED_EXCEPTION_CANCEL) 850 goto error_free_gpt; 851 852 write_back = 1; 853 memset (zeros, 0, disk->dev->sector_size); 854 ped_device_write (disk->dev, zeros, 855 PED_LE64_TO_CPU (gpt->AlternateLBA), 856 1); 857 #endif /* !DISCOVER_ONLY */ 858 } 859 } else { /* primary GPT *not* ok */ 860 int alternate_ok = 0; 861 862 #ifndef DISCOVER_ONLY 863 write_back = 1; 864 #endif 865 866 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) 867 < disk->dev->length - 1) { 868 alternate_ok = _read_header (disk->dev, &gpt, 869 PED_LE64_TO_CPU(gpt->AlternateLBA)); 870 } 871 if (!alternate_ok) { 872 alternate_ok = _read_header (disk->dev, &gpt, 873 disk->dev->length - 1); 874 } 875 876 if (alternate_ok) { 877 if (ped_exception_throw ( 878 PED_EXCEPTION_ERROR, 879 PED_EXCEPTION_OK_CANCEL, 880 _("The primary GPT table is corrupt, but the " 881 "backup appears OK, so that will be used.")) 882 == PED_EXCEPTION_CANCEL) 883 goto error_free_gpt; 884 } else { 885 ped_exception_throw ( 886 PED_EXCEPTION_ERROR, 887 PED_EXCEPTION_CANCEL, 888 _("Both the primary and backup GPT tables " 889 "are corrupt. Try making a fresh table, " 890 "and using Parted's rescue feature to " 891 "recover partitions.")); 892 goto error; 893 } 894 } 895 896 if (!_parse_header (disk, gpt, &write_back)) 897 goto error_free_gpt; 898 899 /* 900 * ptes_size is in bytes and must be a multiple of sector_size. 901 */ 902 ptes_size = ped_round_up_to( 903 sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count, 904 disk->dev->sector_size); 905 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size); 906 907 if (!ped_device_read (disk->dev, ptes, 908 PED_LE64_TO_CPU(gpt->PartitionEntryLBA), 909 ptes_size / disk->dev->sector_size)) 910 goto error_free_ptes; 911 912 for (i = 0; i < gpt_disk_data->entry_count; i++) { 913 PedPartition* part; 914 PedConstraint* constraint_exact; 915 916 if (!guid_cmp (ptes[i].PartitionTypeGuid, UNUSED_ENTRY_GUID)) 917 continue; 918 919 part = _parse_part_entry (disk, &ptes[i]); 920 if (!part) 921 goto error_delete_all; 922 923 part->fs_type = ped_file_system_probe (&part->geom); 924 part->num = i + 1; 925 926 constraint_exact = ped_constraint_exact (&part->geom); 927 if (!ped_disk_add_partition(disk, part, constraint_exact)) { 928 ped_partition_destroy (part); 929 goto error_delete_all; 930 } 931 ped_constraint_destroy (constraint_exact); 932 } 933 ped_free (ptes); 934 935 #ifndef DISCOVER_ONLY 936 if (write_back) 937 ped_disk_commit_to_dev (disk); 938 #endif 939 940 return 1; 941 942 error_delete_all: 943 ped_disk_delete_all (disk); 944 error_free_ptes: 945 ped_free (ptes); 946 error_free_gpt: 947 pth_free (gpt); 948 error: 949 return 0; 950 } 951 952 #ifndef DISCOVER_ONLY 953 /* Writes the protective MBR (to keep DOS happy) */ 954 static int 955 _write_pmbr (PedDevice * dev) 956 { 957 LegacyMBR_t pmbr; 958 959 memset(&pmbr, 0, sizeof(pmbr)); 960 pmbr.Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE); 961 pmbr.PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI; 962 pmbr.PartitionRecord[0].StartSector = 1; 963 pmbr.PartitionRecord[0].EndHead = 0xFE; 964 pmbr.PartitionRecord[0].EndSector = 0xFF; 965 pmbr.PartitionRecord[0].EndTrack = 0xFF; 966 pmbr.PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1); 967 if ((dev->length - 1ULL) > 0xFFFFFFFFULL) 968 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF); 969 else 970 pmbr.PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL); 971 972 return ped_device_write (dev, &pmbr, GPT_PMBR_LBA, GPT_PMBR_SECTORS); 973 } 974 975 static void 976 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc, 977 GuidPartitionTableHeader_t** gpt_p) 978 { 979 GPTDiskData* gpt_disk_data = disk->disk_specific; 980 GuidPartitionTableHeader_t* gpt; 981 982 *gpt_p = pth_new_zeroed (disk->dev); 983 984 gpt = *gpt_p; 985 986 gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE); 987 gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00); 988 989 /* per 1.00 spec */ 990 gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev)); 991 gpt->HeaderCRC32 = 0; 992 gpt->Reserved1 = 0; 993 994 if (alternate) { 995 /* 996 * ptes_size is in sectors 997 */ 998 PedSector ptes_size = ped_div_round_up( 999 gpt_disk_data->entry_count * 1000 sizeof (GuidPartitionEntry_t), 1001 disk->dev->sector_size); 1002 1003 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1); 1004 gpt->AlternateLBA = PED_CPU_TO_LE64 (1); 1005 gpt->PartitionEntryLBA 1006 = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size); 1007 } else { 1008 gpt->MyLBA = PED_CPU_TO_LE64 (1); 1009 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1); 1010 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2); 1011 } 1012 1013 gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start); 1014 gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end); 1015 gpt->DiskGUID = gpt_disk_data->uuid; 1016 gpt->NumberOfPartitionEntries 1017 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count); 1018 gpt->SizeOfPartitionEntry 1019 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t)); 1020 gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc); 1021 gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt)); 1022 } 1023 1024 static void 1025 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte) 1026 { 1027 GPTPartitionData* gpt_part_data = part->disk_specific; 1028 unsigned int i; 1029 1030 PED_ASSERT (gpt_part_data != NULL, return); 1031 1032 pte->PartitionTypeGuid = gpt_part_data->type; 1033 pte->UniquePartitionGuid = gpt_part_data->uuid; 1034 pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start); 1035 pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end); 1036 memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t)); 1037 1038 if (gpt_part_data->hidden) 1039 pte->Attributes.RequiredToFunction = 1; 1040 1041 for (i = 0; i < 72 / sizeof(efi_char16_t); i++) 1042 pte->PartitionName[i] 1043 = (efi_char16_t) PED_CPU_TO_LE16( 1044 (uint16_t) gpt_part_data->name[i]); 1045 } 1046 1047 static int 1048 gpt_write(const PedDisk * disk) 1049 { 1050 GPTDiskData* gpt_disk_data; 1051 GuidPartitionEntry_t* ptes; 1052 uint32_t ptes_crc; 1053 uint8_t* pth_raw = ped_malloc (pth_get_size (disk->dev)); 1054 GuidPartitionTableHeader_t* gpt; 1055 PedPartition* part; 1056 int ptes_size; 1057 1058 PED_ASSERT (disk != NULL, goto error); 1059 PED_ASSERT (disk->dev != NULL, goto error); 1060 PED_ASSERT (disk->disk_specific != NULL, goto error); 1061 1062 gpt_disk_data = disk->disk_specific; 1063 1064 /* 1065 * ptes_size is in bytes and must be a multiple of sector_size. 1066 */ 1067 ptes_size = ped_round_up_to( 1068 sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count, 1069 disk->dev->sector_size); 1070 ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size); 1071 if (!ptes) 1072 goto error; 1073 memset (ptes, 0, ptes_size); 1074 for (part = ped_disk_next_partition (disk, NULL); part; 1075 part = ped_disk_next_partition (disk, part)) { 1076 if (part->type != 0) 1077 continue; 1078 _partition_generate_part_entry (part, &ptes[part->num - 1]); 1079 } 1080 1081 ptes_crc = efi_crc32 (ptes, ptes_size); 1082 1083 /* Write protective MBR */ 1084 if (!_write_pmbr (disk->dev)) 1085 goto error_free_ptes; 1086 1087 /* Write PTH and PTEs */ 1088 _generate_header (disk, 0, ptes_crc, &gpt); 1089 pth_raw = pth_get_raw (disk->dev, gpt); 1090 if (!ped_device_write (disk->dev, pth_raw, 1, 1)) 1091 goto error_free_ptes; 1092 if (!ped_device_write (disk->dev, ptes, 2, ptes_size / disk->dev->sector_size)) 1093 goto error_free_ptes; 1094 1095 /* Write Alternate PTH & PTEs */ 1096 _generate_header (disk, 1, ptes_crc, &gpt); 1097 pth_raw = pth_get_raw (disk->dev, gpt); 1098 if (!ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1)) 1099 goto error_free_ptes; 1100 if (!ped_device_write (disk->dev, ptes, 1101 disk->dev->length - 1 - ptes_size / disk->dev->sector_size, 1102 ptes_size / disk->dev->sector_size)) 1103 goto error_free_ptes; 1104 1105 ped_free (ptes); 1106 return ped_device_sync (disk->dev); 1107 1108 error_free_ptes: 1109 ped_free (ptes); 1110 error: 1111 return 0; 1112 } 1113 #endif /* !DISCOVER_ONLY */ 1114 1115 static int 1116 add_metadata_part(PedDisk * disk, PedSector start, PedSector length) 1117 { 1118 PedPartition* part; 1119 PedConstraint* constraint_exact; 1120 PED_ASSERT(disk != NULL, return 0); 1121 1122 part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 1123 start, start + length - 1); 1124 if (!part) 1125 goto error; 1126 1127 constraint_exact = ped_constraint_exact (&part->geom); 1128 if (!ped_disk_add_partition (disk, part, constraint_exact)) 1129 goto error_destroy_constraint; 1130 ped_constraint_destroy (constraint_exact); 1131 return 1; 1132 1133 error_destroy_constraint: 1134 ped_constraint_destroy (constraint_exact); 1135 ped_partition_destroy (part); 1136 error: 1137 return 0; 1138 } 1139 1140 static PedPartition* 1141 gpt_partition_new (const PedDisk* disk, 1142 PedPartitionType part_type, const PedFileSystemType* fs_type, 1143 PedSector start, PedSector end) 1144 { 1145 PedPartition* part; 1146 GPTPartitionData* gpt_part_data; 1147 1148 part = _ped_partition_alloc (disk, part_type, fs_type, start, end); 1149 if (!part) 1150 goto error; 1151 1152 if (part_type != 0) 1153 return part; 1154 1155 gpt_part_data = part->disk_specific = 1156 ped_malloc (sizeof (GPTPartitionData)); 1157 if (!gpt_part_data) 1158 goto error_free_part; 1159 1160 gpt_part_data->type = PARTITION_BASIC_DATA_GUID; 1161 gpt_part_data->lvm = 0; 1162 gpt_part_data->raid = 0; 1163 gpt_part_data->boot = 0; 1164 gpt_part_data->hp_service = 0; 1165 gpt_part_data->hidden = 0; 1166 gpt_part_data->msftres = 0; 1167 uuid_generate ((unsigned char*) &gpt_part_data->uuid); 1168 swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid)); 1169 strcpy (gpt_part_data->name, ""); 1170 return part; 1171 1172 error_free_part: 1173 _ped_partition_free (part); 1174 error: 1175 return NULL; 1176 } 1177 1178 static PedPartition* 1179 gpt_partition_duplicate (const PedPartition* part) 1180 { 1181 PedPartition* result; 1182 GPTPartitionData* part_data = part->disk_specific; 1183 GPTPartitionData* result_data; 1184 1185 result = _ped_partition_alloc (part->disk, part->type, part->fs_type, 1186 part->geom.start, part->geom.end); 1187 if (!result) 1188 goto error; 1189 result->num = part->num; 1190 1191 if (result->type != 0) 1192 return result; 1193 1194 result_data = result->disk_specific = 1195 ped_malloc (sizeof (GPTPartitionData)); 1196 if (!result_data) 1197 goto error_free_part; 1198 1199 result_data->type = part_data->type; 1200 result_data->uuid = part_data->uuid; 1201 strcpy (result_data->name, part_data->name); 1202 return result; 1203 1204 error_free_part: 1205 _ped_partition_free (result); 1206 error: 1207 return NULL; 1208 } 1209 1210 static void 1211 gpt_partition_destroy (PedPartition *part) 1212 { 1213 if (part->type == 0) { 1214 PED_ASSERT (part->disk_specific != NULL, return); 1215 ped_free (part->disk_specific); 1216 } 1217 1218 _ped_partition_free (part); 1219 } 1220 1221 static int 1222 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type) 1223 { 1224 GPTPartitionData* gpt_part_data = part->disk_specific; 1225 1226 PED_ASSERT (gpt_part_data != NULL, return 0); 1227 1228 part->fs_type = fs_type; 1229 1230 if (gpt_part_data->lvm) { 1231 gpt_part_data->type = PARTITION_LVM_GUID; 1232 return 1; 1233 } 1234 if (gpt_part_data->raid) { 1235 gpt_part_data->type = PARTITION_RAID_GUID; 1236 return 1; 1237 } 1238 if (gpt_part_data->boot) { 1239 gpt_part_data->type = PARTITION_SYSTEM_GUID; 1240 return 1; 1241 } 1242 if (gpt_part_data->hp_service) { 1243 gpt_part_data->type = PARTITION_HPSERVICE_GUID; 1244 return 1; 1245 } 1246 if (gpt_part_data->msftres) { 1247 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID; 1248 return 1; 1249 } 1250 1251 if (fs_type) { 1252 if (strncmp (fs_type->name, "fat", 3) == 0 1253 || strcmp (fs_type->name, "ntfs") == 0) { 1254 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID; 1255 return 1; 1256 } 1257 if (strncmp (fs_type->name, "hfs", 3) == 0) { 1258 gpt_part_data->type = PARTITION_APPLE_HFS_GUID; 1259 return 1; 1260 } 1261 if (strstr (fs_type->name, "swap")) { 1262 gpt_part_data->type = PARTITION_SWAP_GUID; 1263 return 1; 1264 } 1265 } 1266 1267 gpt_part_data->type = PARTITION_BASIC_DATA_GUID; 1268 return 1; 1269 } 1270 1271 /* Allocate metadata partitions for the GPTH and PTES */ 1272 static int 1273 gpt_alloc_metadata (PedDisk * disk) 1274 { 1275 PedSector gptlength, pteslength = 0; 1276 GPTDiskData *gpt_disk_data; 1277 1278 PED_ASSERT(disk != NULL, return 0); 1279 PED_ASSERT(disk->dev != NULL, return 0); 1280 PED_ASSERT(disk->disk_specific != NULL, return 0); 1281 gpt_disk_data = disk->disk_specific; 1282 1283 gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t), 1284 disk->dev->sector_size); 1285 pteslength = ped_div_round_up (gpt_disk_data->entry_count 1286 * sizeof (GuidPartitionEntry_t), disk->dev->sector_size); 1287 1288 /* metadata at the start of the disk includes the MBR */ 1289 if (!add_metadata_part(disk, GPT_PMBR_LBA, 1290 GPT_PMBR_SECTORS + gptlength + pteslength)) 1291 return 0; 1292 1293 /* metadata at the end of the disk */ 1294 if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength, 1295 gptlength + pteslength)) 1296 return 0; 1297 1298 return 1; 1299 } 1300 1301 /* Does nothing, as the read/new/destroy functions maintain part->num */ 1302 static int 1303 gpt_partition_enumerate (PedPartition* part) 1304 { 1305 GPTDiskData* gpt_disk_data = part->disk->disk_specific; 1306 int i; 1307 1308 /* never change the partition numbers */ 1309 if (part->num != -1) 1310 return 1; 1311 1312 for (i = 1; i <= gpt_disk_data->entry_count; i++) { 1313 if (!ped_disk_get_partition (part->disk, i)) { 1314 part->num = i; 1315 return 1; 1316 } 1317 } 1318 1319 PED_ASSERT (0, return 0); 1320 1321 return 0; /* used if debug is disabled */ 1322 } 1323 1324 static int 1325 gpt_partition_set_flag(PedPartition *part, 1326 PedPartitionFlag flag, 1327 int state) 1328 { 1329 GPTPartitionData *gpt_part_data; 1330 PED_ASSERT(part != NULL, return 0); 1331 PED_ASSERT(part->disk_specific != NULL, return 0); 1332 gpt_part_data = part->disk_specific; 1333 1334 switch (flag) { 1335 case PED_PARTITION_BOOT: 1336 gpt_part_data->boot = state; 1337 if (state) 1338 gpt_part_data->raid 1339 = gpt_part_data->lvm 1340 = gpt_part_data->hp_service 1341 = gpt_part_data->msftres = 0; 1342 return gpt_partition_set_system (part, part->fs_type); 1343 case PED_PARTITION_RAID: 1344 gpt_part_data->raid = state; 1345 if (state) 1346 gpt_part_data->boot 1347 = gpt_part_data->lvm 1348 = gpt_part_data->hp_service 1349 = gpt_part_data->msftres = 0; 1350 return gpt_partition_set_system (part, part->fs_type); 1351 case PED_PARTITION_LVM: 1352 gpt_part_data->lvm = state; 1353 if (state) 1354 gpt_part_data->boot 1355 = gpt_part_data->raid 1356 = gpt_part_data->hp_service 1357 = gpt_part_data->msftres = 0; 1358 return gpt_partition_set_system (part, part->fs_type); 1359 case PED_PARTITION_HPSERVICE: 1360 gpt_part_data->hp_service = state; 1361 if (state) 1362 gpt_part_data->boot 1363 = gpt_part_data->raid 1364 = gpt_part_data->lvm 1365 = gpt_part_data->msftres = 0; 1366 return gpt_partition_set_system (part, part->fs_type); 1367 case PED_PARTITION_MSFT_RESERVED: 1368 gpt_part_data->msftres = state; 1369 if (state) 1370 gpt_part_data->boot 1371 = gpt_part_data->raid 1372 = gpt_part_data->lvm 1373 = gpt_part_data->hp_service = 0; 1374 return gpt_partition_set_system (part, part->fs_type); 1375 case PED_PARTITION_HIDDEN: 1376 gpt_part_data->hidden = state; 1377 return 1; 1378 case PED_PARTITION_SWAP: 1379 case PED_PARTITION_ROOT: 1380 case PED_PARTITION_LBA: 1381 default: 1382 return 0; 1383 } 1384 return 1; 1385 } 1386 1387 static int 1388 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag) 1389 { 1390 GPTPartitionData *gpt_part_data; 1391 PED_ASSERT(part->disk_specific != NULL, return 0); 1392 gpt_part_data = part->disk_specific; 1393 1394 switch (flag) { 1395 case PED_PARTITION_RAID: 1396 return gpt_part_data->raid; 1397 case PED_PARTITION_LVM: 1398 return gpt_part_data->lvm; 1399 case PED_PARTITION_BOOT: 1400 return gpt_part_data->boot; 1401 case PED_PARTITION_HPSERVICE: 1402 return gpt_part_data->hp_service; 1403 case PED_PARTITION_MSFT_RESERVED: 1404 return gpt_part_data->msftres; 1405 case PED_PARTITION_HIDDEN: 1406 return gpt_part_data->hidden; 1407 case PED_PARTITION_SWAP: 1408 case PED_PARTITION_LBA: 1409 case PED_PARTITION_ROOT: 1410 default: 1411 return 0; 1412 } 1413 return 0; 1414 } 1415 1416 static int 1417 gpt_partition_is_flag_available(const PedPartition * part, 1418 PedPartitionFlag flag) 1419 { 1420 switch (flag) { 1421 case PED_PARTITION_RAID: 1422 case PED_PARTITION_LVM: 1423 case PED_PARTITION_BOOT: 1424 case PED_PARTITION_HPSERVICE: 1425 case PED_PARTITION_MSFT_RESERVED: 1426 case PED_PARTITION_HIDDEN: 1427 return 1; 1428 case PED_PARTITION_SWAP: 1429 case PED_PARTITION_ROOT: 1430 case PED_PARTITION_LBA: 1431 default: 1432 return 0; 1433 } 1434 return 0; 1435 } 1436 1437 static void 1438 gpt_partition_set_name (PedPartition *part, const char *name) 1439 { 1440 GPTPartitionData *gpt_part_data = part->disk_specific; 1441 1442 strncpy (gpt_part_data->name, name, 36); 1443 gpt_part_data->name [36] = 0; 1444 } 1445 1446 static const char * 1447 gpt_partition_get_name (const PedPartition * part) 1448 { 1449 GPTPartitionData* gpt_part_data = part->disk_specific; 1450 return gpt_part_data->name; 1451 } 1452 1453 static int 1454 gpt_get_max_primary_partition_count (const PedDisk *disk) 1455 { 1456 const GPTDiskData* gpt_disk_data = disk->disk_specific; 1457 return gpt_disk_data->entry_count; 1458 } 1459 1460 static PedConstraint* 1461 _non_metadata_constraint (const PedDisk* disk) 1462 { 1463 GPTDiskData* gpt_disk_data = disk->disk_specific; 1464 1465 return ped_constraint_new_from_max (&gpt_disk_data->data_area); 1466 } 1467 1468 static int 1469 gpt_partition_align (PedPartition* part, const PedConstraint* constraint) 1470 { 1471 PED_ASSERT (part != NULL, return 0); 1472 1473 if (_ped_partition_attempt_align (part, constraint, 1474 _non_metadata_constraint (part->disk))) 1475 return 1; 1476 1477 #ifndef DISCOVER_ONLY 1478 ped_exception_throw ( 1479 PED_EXCEPTION_ERROR, 1480 PED_EXCEPTION_CANCEL, 1481 _("Unable to satisfy all constraints on the partition.")); 1482 #endif 1483 return 0; 1484 } 1485 1486 static PedDiskOps gpt_disk_ops = { 1487 .probe = gpt_probe, 1488 #ifndef DISCOVER_ONLY 1489 .clobber = gpt_clobber, 1490 #else 1491 .clobber = NULL, 1492 #endif 1493 .alloc = gpt_alloc, 1494 .duplicate = gpt_duplicate, 1495 .free = gpt_free, 1496 .read = gpt_read, 1497 #ifndef DISCOVER_ONLY 1498 .write = gpt_write, 1499 #else 1500 .write = NULL, 1501 #endif 1502 1503 .partition_new = gpt_partition_new, 1504 .partition_duplicate = gpt_partition_duplicate, 1505 .partition_destroy = gpt_partition_destroy, 1506 .partition_set_system = gpt_partition_set_system, 1507 .partition_set_flag = gpt_partition_set_flag, 1508 .partition_get_flag = gpt_partition_get_flag, 1509 .partition_is_flag_available = gpt_partition_is_flag_available, 1510 .partition_set_name = gpt_partition_set_name, 1511 .partition_get_name = gpt_partition_get_name, 1512 .partition_align = gpt_partition_align, 1513 .partition_enumerate = gpt_partition_enumerate, 1514 .alloc_metadata = gpt_alloc_metadata, 1515 .get_max_primary_partition_count = gpt_get_max_primary_partition_count 1516 }; 1517 1518 static PedDiskType gpt_disk_type = { 1519 .next = NULL, 1520 .name = "gpt", 1521 .ops = &gpt_disk_ops, 1522 .features = PED_DISK_TYPE_PARTITION_NAME 1523 }; 1524 1525 void 1526 ped_disk_gpt_init() 1527 { 1528 PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return); 1529 PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return); 1530 1531 ped_disk_type_register (&gpt_disk_type); 1532 } 1533 1534 void 1535 ped_disk_gpt_done() 1536 { 1537 ped_disk_type_unregister (&gpt_disk_type); 1538 }