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 }