OSDN Git Service

gpt: verify CRC32 of partition table entry array, too
[android-x86/external-parted.git] / libparted / labels / gpt.c
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-2003, 2005-2009 Free Software Foundation, Inc.
8
9     EFI GUID Partition Table handling
10     Per Intel EFI Specification v1.02
11     http://developer.intel.com/technology/efi/efi.htm
12
13     This program is free software; you can redistribute it and/or modify
14     it under the terms of the GNU General Public License as published by
15     the Free Software Foundation; either version 3 of the License, or
16     (at your option) any later version.
17
18     This program is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21     GNU General Public License for more details.
22
23     You should have received a copy of the GNU General Public License
24     along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 */
26
27 #include <config.h>
28
29 #include <parted/parted.h>
30 #include <parted/debug.h>
31 #include <parted/endian.h>
32 #include <parted/crc32.h>
33 #include <inttypes.h>
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <uuid/uuid.h>
40 #include <stdbool.h>
41 #include "xalloc.h"
42
43 #include "pt-tools.h"
44
45 #if ENABLE_NLS
46 #  include <libintl.h>
47 #  define _(String) gettext (String)
48 #else
49 #  define _(String) (String)
50 #endif                          /* ENABLE_NLS */
51
52 #define EFI_PMBR_OSTYPE_EFI 0xEE
53 #define MSDOS_MBR_SIGNATURE 0xaa55
54
55 #define GPT_HEADER_SIGNATURE 0x5452415020494645LL
56
57 /* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
58  * so some implementors got confused...
59  */
60 #define GPT_HEADER_REVISION_V1_02 0x00010200
61 #define GPT_HEADER_REVISION_V1_00 0x00010000
62 #define GPT_HEADER_REVISION_V0_99 0x00009900
63
64 typedef uint16_t efi_char16_t;  /* UNICODE character */
65 typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
66 typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
67 typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
68 typedef struct _PartitionRecord_t PartitionRecord_t;
69 typedef struct _LegacyMBR_t LegacyMBR_t;
70 typedef struct _GPTDiskData GPTDiskData;
71 typedef struct {
72         uint32_t time_low;
73         uint16_t time_mid;
74         uint16_t time_hi_and_version;
75         uint8_t  clock_seq_hi_and_reserved;
76         uint8_t  clock_seq_low;
77         uint8_t  node[6];
78 } /* __attribute__ ((packed)) */ efi_guid_t;
79 /* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
80  * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
81  * data.  It turns out we don't need it in this case, so it doesn't break
82  * anything :)
83  */
84
85 #define UNUSED_ENTRY_GUID    \
86     ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
87                     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
88 #define PARTITION_SYSTEM_GUID \
89     ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
90                     PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
91                     { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
92 #define PARTITION_BIOS_GRUB_GUID \
93     ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
94                     PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
95                     { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
96 #define LEGACY_MBR_PARTITION_GUID \
97     ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
98                     PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
99                     { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
100 #define PARTITION_MSFT_RESERVED_GUID \
101     ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
102                     PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
103                     { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
104 #define PARTITION_BASIC_DATA_GUID \
105     ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
106                     PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
107                     { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
108 #define PARTITION_RAID_GUID \
109     ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
110                     PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
111                     { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
112 #define PARTITION_SWAP_GUID \
113     ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
114                     PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
115                     { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
116 #define PARTITION_LVM_GUID \
117     ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
118                     PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
119                     { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
120 #define PARTITION_RESERVED_GUID \
121     ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
122                     PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
123                     { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
124 #define PARTITION_HPSERVICE_GUID \
125     ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
126                     PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
127                     { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
128 #define PARTITION_APPLE_HFS_GUID \
129     ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
130                     PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
131                     { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
132
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 #ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
153         uint64_t RequiredToFunction:1;
154         uint64_t Reserved:47;
155         uint64_t GuidSpecific:16;
156 #else
157 #       warning "Using crippled partition entry type"
158         uint32_t RequiredToFunction:1;
159         uint32_t Reserved:32;
160         uint32_t LOST:5;
161         uint32_t GuidSpecific:16;
162 #endif
163 };
164
165 struct __attribute__ ((packed)) _GuidPartitionEntry_t {
166         efi_guid_t PartitionTypeGuid;
167         efi_guid_t UniquePartitionGuid;
168         uint64_t StartingLBA;
169         uint64_t EndingLBA;
170         GuidPartitionEntryAttributes_t Attributes;
171         efi_char16_t PartitionName[72 / sizeof(efi_char16_t)];
172 };
173
174 #define GPT_PMBR_LBA 0
175 #define GPT_PMBR_SECTORS 1
176 #define GPT_PRIMARY_HEADER_LBA 1
177 #define GPT_HEADER_SECTORS 1
178 #define GPT_PRIMARY_PART_TABLE_LBA 2
179
180 /*
181    These values are only defaults.  The actual on-disk structures
182    may define different sizes, so use those unless creating a new GPT disk!
183 */
184
185 #define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
186
187 /* Number of actual partition entries should be calculated as: */
188 #define GPT_DEFAULT_PARTITION_ENTRIES \
189         (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
190          sizeof(GuidPartitionEntry_t))
191
192
193 struct __attribute__ ((packed)) _PartitionRecord_t {
194         /* Not used by EFI firmware. Set to 0x80 to indicate that this
195            is the bootable legacy partition. */
196         uint8_t BootIndicator;
197
198         /* Start of partition in CHS address, not used by EFI firmware. */
199         uint8_t StartHead;
200
201         /* Start of partition in CHS address, not used by EFI firmware. */
202         uint8_t StartSector;
203
204         /* Start of partition in CHS address, not used by EFI firmware. */
205         uint8_t StartTrack;
206
207         /* OS type. A value of 0xEF defines an EFI system partition.
208            Other values are reserved for legacy operating systems, and
209            allocated independently of the EFI specification. */
210         uint8_t OSType;
211
212         /* End of partition in CHS address, not used by EFI firmware. */
213         uint8_t EndHead;
214
215         /* End of partition in CHS address, not used by EFI firmware. */
216         uint8_t EndSector;
217
218         /* End of partition in CHS address, not used by EFI firmware. */
219         uint8_t EndTrack;
220
221         /* Starting LBA address of the partition on the disk. Used by
222            EFI firmware to define the start of the partition. */
223         uint32_t StartingLBA;
224
225         /* Size of partition in LBA. Used by EFI firmware to determine
226            the size of the partition. */
227         uint32_t SizeInLBA;
228 };
229
230 /* Protected Master Boot Record  & Legacy MBR share same structure */
231 /* Needs to be packed because the u16s force misalignment. */
232 struct __attribute__ ((packed)) _LegacyMBR_t {
233         uint8_t BootCode[440];
234         uint32_t UniqueMBRSignature;
235         uint16_t Unknown;
236         PartitionRecord_t PartitionRecord[4];
237         uint16_t Signature;
238 };
239
240 /* uses libparted's disk_specific field in PedDisk, to store our info */
241 struct __attribute__ ((packed)) _GPTDiskData {
242         PedGeometry     data_area;
243         int             entry_count;
244         efi_guid_t      uuid;
245 };
246
247 /* uses libparted's disk_specific field in PedPartition, to store our info */
248 typedef struct _GPTPartitionData {
249         efi_guid_t      type;
250         efi_guid_t      uuid;
251         char            name[37];
252         int             lvm;
253         int             raid;
254         int             boot;
255         int             bios_grub;
256         int             hp_service;
257         int             hidden;
258         int             msftres;
259 } GPTPartitionData;
260
261 static PedDiskType gpt_disk_type;
262
263
264 static inline uint32_t
265 pth_get_size (const PedDevice* dev)
266 {
267         return GPT_HEADER_SECTORS * dev->sector_size;
268 }
269
270
271 static inline uint32_t
272 pth_get_size_static (const PedDevice* dev)
273 {
274         return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t*);
275 }
276
277
278 static inline uint32_t
279 pth_get_size_rsv2 (const PedDevice* dev)
280 {
281         return pth_get_size(dev) - pth_get_size_static(dev);
282 }
283
284
285 static GuidPartitionTableHeader_t*
286 pth_new (const PedDevice* dev)
287 {
288         GuidPartitionTableHeader_t* pth = ped_malloc (
289                         sizeof (GuidPartitionTableHeader_t)
290                         + sizeof (uint8_t));
291
292         pth->Reserved2 = ped_malloc ( pth_get_size_rsv2 (dev) );
293
294         return pth;
295 }
296
297
298 static GuidPartitionTableHeader_t*
299 pth_new_zeroed (const PedDevice* dev)
300 {
301         GuidPartitionTableHeader_t* pth = pth_new (dev);
302
303         memset (pth, 0, pth_get_size_static (dev));
304         memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
305
306         return (pth);
307 }
308
309
310 static GuidPartitionTableHeader_t*
311 pth_new_from_raw (const PedDevice* dev, const uint8_t* pth_raw)
312 {
313         GuidPartitionTableHeader_t* pth = pth_new (dev);
314
315         PED_ASSERT (pth_raw != NULL, return 0);
316
317         memcpy (pth, pth_raw, pth_get_size_static (dev));
318         memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
319                         pth_get_size_rsv2 (dev));
320
321         return pth;
322 }
323
324 static void
325 pth_free (GuidPartitionTableHeader_t* pth)
326 {
327         PED_ASSERT (pth != NULL, return);
328         PED_ASSERT (pth->Reserved2 != NULL, return);
329
330         free (pth->Reserved2);
331         free (pth);
332 }
333
334 static uint8_t*
335 pth_get_raw (const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
336 {
337         uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
338         int size_static = pth_get_size_static (dev);
339
340         PED_ASSERT (pth != NULL, return 0);
341         PED_ASSERT (pth->Reserved2 != NULL, return 0);
342
343         memcpy (pth_raw, pth, size_static);
344         memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
345
346         return pth_raw;
347 }
348
349
350 /**
351  * swap_uuid_and_efi_guid() - converts between uuid formats
352  * @uuid - uuid_t in either format (converts it to the other)
353  *
354  * There are two different representations for Globally Unique Identifiers
355  * (GUIDs or UUIDs).
356  *
357  * The RFC specifies a UUID as a string of 16 bytes, essentially
358  * a big-endian array of char.
359  * Intel, in their EFI Specification, references the same RFC, but
360  * then defines a GUID as a structure of little-endian fields.
361  * Coincidentally, both structures have the same format when unparsed.
362  *
363  * When read from disk, EFI GUIDs are in struct of little endian format,
364  * and need to be converted to be treated as uuid_t in memory.
365  *
366  * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
367  *
368  * Blame Intel.
369  */
370 static void
371 swap_uuid_and_efi_guid(uuid_t uuid)
372 {
373         efi_guid_t *guid = (efi_guid_t *)uuid;
374
375         PED_ASSERT(uuid != NULL, return);
376         guid->time_low            = PED_SWAP32(guid->time_low);
377         guid->time_mid            = PED_SWAP16(guid->time_mid);
378         guid->time_hi_and_version = PED_SWAP16(guid->time_hi_and_version);
379 }
380
381 /* returns the EFI-style CRC32 value for buf
382  *      This function uses the crc32 function by Gary S. Brown,
383  * but seeds the function with ~0, and xor's with ~0 at the end.
384  */
385 static inline uint32_t
386 efi_crc32(const void *buf, unsigned long len)
387 {
388         return (__efi_crc32(buf, len, ~0L) ^ ~0L);
389 }
390
391 static inline uint32_t
392 pth_crc32(const PedDevice* dev, const GuidPartitionTableHeader_t* pth)
393 {
394         uint8_t* pth_raw = pth_get_raw (dev, pth);
395         uint32_t crc32 = 0;
396
397         PED_ASSERT (dev != NULL, return 0);
398         PED_ASSERT (pth != NULL, return 0);
399
400         crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
401
402         free (pth_raw);
403
404         return crc32;
405 }
406
407 static inline int
408 guid_cmp (efi_guid_t left, efi_guid_t right)
409 {
410         return memcmp(&left, &right, sizeof(efi_guid_t));
411 }
412
413 /* checks if 'mbr' is a protective MBR partition table */
414 static inline int
415 _pmbr_is_valid (const LegacyMBR_t* mbr)
416 {
417         int i;
418
419         PED_ASSERT(mbr != NULL, return 0);
420
421         if (mbr->Signature != PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE))
422                 return 0;
423         for (i = 0; i < 4; i++) {
424                 if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
425                         return 1;
426         }
427         return 0;
428 }
429
430 static int
431 gpt_probe (const PedDevice * dev)
432 {
433         GuidPartitionTableHeader_t* gpt = NULL;
434         uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
435         int gpt_sig_found = 0;
436
437         PED_ASSERT (dev != NULL, return 0);
438
439         if (ped_device_read(dev, pth_raw, 1, GPT_HEADER_SECTORS)
440         || ped_device_read(dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS)) {
441                 gpt = pth_new_from_raw (dev, pth_raw);
442                 if (gpt->Signature == PED_CPU_TO_LE64(GPT_HEADER_SIGNATURE))
443                         gpt_sig_found = 1;
444         }
445
446         free (pth_raw);
447
448         if (gpt)
449                 pth_free (gpt);
450
451
452         if (!gpt_sig_found)
453                 return 0;
454
455
456         void *label;
457         if (!ptt_read_sector (dev, 0, &label))
458                 return 0;
459
460         int ok = 1;
461         if (!_pmbr_is_valid ( (const LegacyMBR_t *) label)) {
462                 int ex_status = ped_exception_throw (
463                         PED_EXCEPTION_WARNING,
464                         PED_EXCEPTION_YES_NO,
465                 _("%s contains GPT signatures, indicating that it has "
466                   "a GPT table.  However, it does not have a valid "
467                   "fake msdos partition table, as it should.  Perhaps "
468                   "it was corrupted -- possibly by a program that "
469                   "doesn't understand GPT partition tables.  Or "
470                   "perhaps you deleted the GPT table, and are now "
471                   "using an msdos partition table.  Is this a GPT "
472                   "partition table?"),
473                         dev->path);
474                 if (ex_status == PED_EXCEPTION_NO)
475                         ok = 0;
476         }
477
478         free (label);
479         return ok;
480 }
481
482 #ifndef DISCOVER_ONLY
483 /* writes zeros to the PMBR and the primary and alternate GPTHs and PTEs */
484 static int
485 gpt_clobber(PedDevice * dev)
486 {
487         uint8_t* pth_raw = ped_malloc (pth_get_size (dev));
488         GuidPartitionTableHeader_t* gpt;
489
490         PED_ASSERT (dev != NULL, return 0);
491
492         /*
493          * TO DISCUSS: check whether checksum is correct?
494          * If not, we might get a wrong AlternateLBA field and destroy
495          * one sector of random data.
496          */
497         if (!ped_device_read(dev, pth_raw,
498                              GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS)) {
499                 free (pth_raw);
500                 return 0;
501         }
502
503         gpt = pth_new_from_raw (dev, pth_raw);
504         free (pth_raw);
505
506         if (!ptt_clear_sectors(dev, GPT_PMBR_LBA, GPT_PMBR_SECTORS))
507                 goto error_free_with_gpt;
508         if (!ptt_clear_sectors(dev, GPT_PRIMARY_HEADER_LBA, GPT_HEADER_SECTORS))
509                 goto error_free_with_gpt;
510         if (!ptt_clear_sectors(dev, dev->length - GPT_HEADER_SECTORS,
511                                GPT_HEADER_SECTORS))
512                 goto error_free_with_gpt;
513
514         if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA) < dev->length - 1) {
515                 if (!ped_device_write(dev, gpt,
516                                       PED_LE64_TO_CPU (gpt->AlternateLBA),
517                                       GPT_HEADER_SECTORS))
518                         return 0;
519         }
520
521         pth_free (gpt);
522
523         return 1;
524
525 error_free_with_gpt:
526         pth_free (gpt);
527         return 0;
528 }
529 #endif /* !DISCOVER_ONLY */
530
531 static PedDisk *
532 gpt_alloc (const PedDevice * dev)
533 {
534         PedDisk* disk;
535         GPTDiskData *gpt_disk_data;
536         PedSector data_start, data_end;
537
538         disk = _ped_disk_alloc ((PedDevice*)dev, &gpt_disk_type);
539         if (!disk)
540                 goto error;
541         disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
542         if (!disk->disk_specific)
543                 goto error_free_disk;
544
545         data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
546         data_end = dev->length - 2
547                    - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
548         ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
549                            data_end - data_start + 1);
550         gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
551         uuid_generate ((unsigned char*) &gpt_disk_data->uuid);
552         swap_uuid_and_efi_guid((unsigned char*)(&gpt_disk_data->uuid));
553         return disk;
554
555 error_free_disk:
556         free (disk);
557 error:
558         return NULL;
559 }
560
561 static PedDisk*
562 gpt_duplicate (const PedDisk* disk)
563 {
564         PedDisk* new_disk;
565         GPTDiskData* new_disk_data;
566         GPTDiskData* old_disk_data;
567
568         new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
569         if (!new_disk)
570                 return NULL;
571
572         old_disk_data = disk->disk_specific;
573         new_disk_data = new_disk->disk_specific;
574
575         ped_geometry_init (&new_disk_data->data_area, disk->dev,
576                            old_disk_data->data_area.start,
577                            old_disk_data->data_area.length);
578         new_disk_data->entry_count = old_disk_data->entry_count;
579         new_disk_data->uuid = old_disk_data->uuid;
580         return new_disk;
581 }
582
583 static void
584 gpt_free(PedDisk * disk)
585 {
586         ped_disk_delete_all (disk);
587         free (disk->disk_specific);
588         _ped_disk_free (disk);
589 }
590
591 static int
592 _header_is_valid (const PedDevice* dev, GuidPartitionTableHeader_t* gpt)
593 {
594         uint32_t crc, origcrc;
595
596         if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
597                 return 0;
598         /*
599          * "While the GUID Partition Table Header's size may increase
600          * in the future it cannot span more than one block on the
601          * device."  EFI Specification, version 1.10, 11.2.2.1
602          */
603         if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
604             || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
605                 return 0;
606
607         /*
608          * the SizeOfPartitionEntry must be a multiple of 8 and
609          * no smaller than the size of the PartitionEntry structure.
610          */
611         uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
612         if (sope % 8 != 0
613             || sope < sizeof (GuidPartitionEntry_t)
614             || (UINT32_MAX >> 4) < sope)
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                 free (pth_raw);
635                 return 0;
636         }
637
638         *gpt = pth_new_from_raw (dev, pth_raw);
639
640         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                 = (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, PED_PARTITION_NORMAL, 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
773                 = gpt_part_data->bios_grub = 0;
774
775         if (pte->Attributes.RequiredToFunction & 0x1)
776                 gpt_part_data->hidden = 1;
777
778         if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
779                 gpt_part_data->boot = 1;
780         else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
781                 gpt_part_data->bios_grub = 1;
782         else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
783                 gpt_part_data->raid = 1;
784         else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
785                 gpt_part_data->lvm = 1;
786         else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
787                 gpt_part_data->hp_service = 1;
788         else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
789                 gpt_part_data->msftres = 1;
790
791         return part;
792 }
793
794 /************************************************************
795  *  Intel is changing the EFI Spec. (after v1.02) to say that a
796  *  disk is considered to have a GPT label only if the GPT
797  *  structures are correct, and the MBR is actually a Protective
798  *  MBR (has one 0xEE type partition).
799  *  Problem occurs when a GPT-partitioned disk is then
800  *  edited with a legacy (non-GPT-aware) application, such as
801  *  fdisk (which doesn't generally erase the PGPT or AGPT).
802  *  How should such a disk get handled?  As a GPT disk (throwing
803  *  away the fdisk changes), or as an MSDOS disk (throwing away
804  *  the GPT information).  Previously, I've taken the GPT-is-right,
805  *  MBR is wrong, approach, to stay consistent with the EFI Spec.
806  *  Intel disagrees, saying the disk should then be treated
807  *  as having a msdos label, not a GPT label.  If this is true,
808  *  then what's the point of having an AGPT, since if the PGPT
809  *  is screwed up, likely the PMBR is too, and the PMBR becomes
810  *  a single point of failure.
811  *  So, in the Linux kernel, I'm going to test for PMBR, and
812  *  warn if it's not there, and treat the disk as MSDOS, with a note
813  *  for users to use Parted to "fix up" their disk if they
814  *  really want it to be considered GPT.
815  ************************************************************/
816 static int
817 gpt_read (PedDisk * disk)
818 {
819         GPTDiskData *gpt_disk_data = disk->disk_specific;
820         GuidPartitionTableHeader_t* gpt;
821         void* ptes;
822         int i;
823 #ifndef DISCOVER_ONLY
824         int write_back = 0;
825 #endif
826
827         ped_disk_delete_all (disk);
828
829         /*
830          * motivation: let the user decide about the pmbr... during
831          * ped_disk_probe(), they probably didn't get a choice...
832          */
833         if (!gpt_probe (disk->dev))
834                 goto error;
835
836         if (_read_header (disk->dev, &gpt, 1)) {
837                 /* There used to be a GPT partition table here, with an
838                    alternate LBA that extended beyond the current
839                    end-of-device.  Treat it as a non-match.   */
840                 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
841                     > disk->dev->length - 1)
842                         goto error_free_gpt;
843
844                 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
845                                 < disk->dev->length - 1) {
846
847 #ifndef DISCOVER_ONLY
848                         switch (ped_exception_throw (
849                                 PED_EXCEPTION_ERROR,
850                                 PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL | PED_EXCEPTION_IGNORE,
851                 _("The backup GPT table is not at the end of the disk, as it "
852                   "should be.  This might mean that another operating system "
853                   "believes the disk is smaller.  Fix, by moving the backup "
854                   "to the end (and removing the old backup)?"))) {
855                                 case PED_EXCEPTION_CANCEL:
856                                         goto error_free_gpt;
857                                 case PED_EXCEPTION_FIX:
858                                         {
859                                         char *zeros =
860                                           ped_malloc (pth_get_size (disk->dev));
861                                         write_back = 1;
862                                         memset (zeros, 0, disk->dev->sector_size);
863                                         ped_device_write (disk->dev, zeros,
864                                                           PED_LE64_TO_CPU (gpt->AlternateLBA),
865                                                           1);
866                                         free (zeros);
867                                         }
868                                         break;
869                                 default:
870                                         break;
871                         }
872
873 #endif /* !DISCOVER_ONLY */
874                 }
875         } else { /* primary GPT *not* ok */
876                 int alternate_ok = 0;
877
878 #ifndef DISCOVER_ONLY
879                 write_back = 1;
880 #endif
881
882                 if ((PedSector) PED_LE64_TO_CPU (gpt->AlternateLBA)
883                                 < disk->dev->length - 1) {
884                         alternate_ok = _read_header (disk->dev, &gpt,
885                                             PED_LE64_TO_CPU(gpt->AlternateLBA));
886                 }
887                 if (!alternate_ok) {
888                         alternate_ok = _read_header (disk->dev, &gpt,
889                                                      disk->dev->length - 1);
890                 }
891
892                 if (alternate_ok) {
893                         if (ped_exception_throw (
894                                 PED_EXCEPTION_ERROR,
895                                 PED_EXCEPTION_OK_CANCEL,
896                                 _("The primary GPT table is corrupt, but the "
897                                   "backup appears OK, so that will be used."))
898                                     == PED_EXCEPTION_CANCEL)
899                                 goto error_free_gpt;
900                 } else {
901                         ped_exception_throw (
902                                 PED_EXCEPTION_ERROR,
903                                 PED_EXCEPTION_CANCEL,
904                                 _("Both the primary and backup GPT tables "
905                                   "are corrupt.  Try making a fresh table, "
906                                   "and using Parted's rescue feature to "
907                                   "recover partitions."));
908                         goto error;
909                 }
910         }
911
912         if (!_parse_header (disk, gpt, &write_back))
913                 goto error_free_gpt;
914
915         uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
916         size_t ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
917         size_t ptes_sectors = ped_div_round_up (ptes_bytes,
918                                                 disk->dev->sector_size);
919
920         if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
921                 goto error_free_gpt;
922         ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
923
924         if (!ped_device_read (disk->dev, ptes,
925                               PED_LE64_TO_CPU(gpt->PartitionEntryLBA),
926                               ptes_sectors))
927                 goto error_free_ptes;
928
929         uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
930         if (ptes_crc != gpt->PartitionEntryArrayCRC32) {
931                 ped_exception_throw (
932                         PED_EXCEPTION_ERROR,
933                         PED_EXCEPTION_CANCEL,
934                         _("partition table array (FIXME:which?) CRC mismatch"));
935                 goto error_free_ptes;
936         }
937
938         for (i = 0; i < gpt_disk_data->entry_count; i++) {
939                 GuidPartitionEntry_t* pte
940                   = (GuidPartitionEntry_t*) ((char *)ptes + i * p_ent_size);
941                 PedPartition* part;
942                 PedConstraint* constraint_exact;
943
944                 if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
945                         continue;
946
947                 part = _parse_part_entry (disk, pte);
948                 if (!part)
949                         goto error_delete_all;
950
951                 part->fs_type = ped_file_system_probe (&part->geom);
952                 part->num = i + 1;
953
954                 constraint_exact = ped_constraint_exact (&part->geom);
955                 if (!ped_disk_add_partition(disk, part, constraint_exact)) {
956                         ped_partition_destroy (part);
957                         goto error_delete_all;
958                 }
959                 ped_constraint_destroy (constraint_exact);
960         }
961         free (ptes);
962
963 #ifndef DISCOVER_ONLY
964         if (write_back)
965                 ped_disk_commit_to_dev (disk);
966 #endif
967
968         pth_free (gpt);
969         return 1;
970
971 error_delete_all:
972         ped_disk_delete_all (disk);
973 error_free_ptes:
974         free (ptes);
975 error_free_gpt:
976         pth_free (gpt);
977 error:
978         return 0;
979 }
980
981 #ifndef DISCOVER_ONLY
982 /* Write the protective MBR (to keep DOS happy) */
983 static int
984 _write_pmbr (PedDevice * dev)
985 {
986         /* The UEFI spec is not clear about what to do with the following
987            elements of the Protective MBR (pmbr): BootCode (0-440B),
988            UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
989            With this in mind, we try not to modify these elements.  */
990         void *s0;
991         if (!ptt_read_sector (dev, 0, &s0))
992                 return 0;
993         LegacyMBR_t *pmbr = s0;
994
995         /* Zero out the legacy partitions.  */
996         memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
997
998         pmbr->Signature = PED_CPU_TO_LE16(MSDOS_MBR_SIGNATURE);
999         pmbr->PartitionRecord[0].OSType      = EFI_PMBR_OSTYPE_EFI;
1000         pmbr->PartitionRecord[0].StartSector = 1;
1001         pmbr->PartitionRecord[0].EndHead     = 0xFE;
1002         pmbr->PartitionRecord[0].EndSector   = 0xFF;
1003         pmbr->PartitionRecord[0].EndTrack    = 0xFF;
1004         pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32(1);
1005         if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1006                 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(0xFFFFFFFF);
1007         else
1008                 pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32(dev->length - 1UL);
1009
1010         int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1011                                          GPT_PMBR_SECTORS);
1012         free (s0);
1013         return write_ok;
1014 }
1015
1016 static void
1017 _generate_header (const PedDisk* disk, int alternate, uint32_t ptes_crc,
1018                   GuidPartitionTableHeader_t** gpt_p)
1019 {
1020         GPTDiskData* gpt_disk_data = disk->disk_specific;
1021         GuidPartitionTableHeader_t* gpt;
1022
1023         *gpt_p = pth_new_zeroed (disk->dev);
1024
1025         gpt = *gpt_p;
1026
1027         gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1028         gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1029
1030         /* per 1.00 spec */
1031         gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1032         gpt->HeaderCRC32 = 0;
1033         gpt->Reserved1 = 0;
1034
1035         if (alternate) {
1036                 PedSector ptes_size = gpt_disk_data->entry_count
1037                                       * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1038
1039                 gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1040                 gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1041                 gpt->PartitionEntryLBA
1042                         = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1043         } else {
1044                 gpt->MyLBA = PED_CPU_TO_LE64 (1);
1045                 gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1046                 gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1047         }
1048
1049         gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1050         gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1051         gpt->DiskGUID = gpt_disk_data->uuid;
1052         gpt->NumberOfPartitionEntries
1053                 = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1054         gpt->SizeOfPartitionEntry
1055                 = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1056         gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1057         gpt->HeaderCRC32 = PED_CPU_TO_LE32 (pth_crc32 (disk->dev, gpt));
1058 }
1059
1060 static void
1061 _partition_generate_part_entry (PedPartition* part, GuidPartitionEntry_t* pte)
1062 {
1063         GPTPartitionData* gpt_part_data = part->disk_specific;
1064         unsigned int i;
1065
1066         PED_ASSERT (gpt_part_data != NULL, return);
1067
1068         pte->PartitionTypeGuid = gpt_part_data->type;
1069         pte->UniquePartitionGuid = gpt_part_data->uuid;
1070         pte->StartingLBA = PED_CPU_TO_LE64(part->geom.start);
1071         pte->EndingLBA = PED_CPU_TO_LE64(part->geom.end);
1072         memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1073
1074         if (gpt_part_data->hidden)
1075                 pte->Attributes.RequiredToFunction = 1;
1076
1077         for (i = 0; i < 72 / sizeof(efi_char16_t); i++)
1078                 pte->PartitionName[i]
1079                         = (efi_char16_t) PED_CPU_TO_LE16(
1080                                 (uint16_t) gpt_part_data->name[i]);
1081 }
1082
1083 static int
1084 gpt_write(const PedDisk * disk)
1085 {
1086         GPTDiskData* gpt_disk_data;
1087         GuidPartitionEntry_t* ptes;
1088         uint32_t ptes_crc;
1089         uint8_t* pth_raw;
1090         GuidPartitionTableHeader_t* gpt;
1091         PedPartition* part;
1092         int ptes_size;
1093
1094         PED_ASSERT (disk != NULL, goto error);
1095         PED_ASSERT (disk->dev != NULL, goto error);
1096         PED_ASSERT (disk->disk_specific != NULL, goto error);
1097
1098         gpt_disk_data = disk->disk_specific;
1099
1100         ptes_size = sizeof (GuidPartitionEntry_t) * gpt_disk_data->entry_count;
1101         ptes = (GuidPartitionEntry_t*) ped_malloc (ptes_size);
1102         if (!ptes)
1103                 goto error;
1104         memset (ptes, 0, ptes_size);
1105         for (part = ped_disk_next_partition (disk, NULL); part;
1106              part = ped_disk_next_partition (disk, part)) {
1107                 if (part->type != 0)
1108                         continue;
1109                 _partition_generate_part_entry (part, &ptes[part->num - 1]);
1110         }
1111
1112         ptes_crc = efi_crc32 (ptes, ptes_size);
1113
1114         /* Write protective MBR */
1115         if (!_write_pmbr (disk->dev))
1116                 goto error_free_ptes;
1117
1118         /* Write PTH and PTEs */
1119         _generate_header (disk, 0, ptes_crc, &gpt);
1120         pth_raw = pth_get_raw (disk->dev, gpt);
1121         pth_free (gpt);
1122         bool write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1123         free (pth_raw);
1124         if (!write_ok)
1125                 goto error_free_ptes;
1126         if (!ped_device_write (disk->dev, ptes, 2,
1127                                ptes_size / disk->dev->sector_size))
1128                 goto error_free_ptes;
1129
1130         /* Write Alternate PTH & PTEs */
1131         _generate_header (disk, 1, ptes_crc, &gpt);
1132         pth_raw = pth_get_raw (disk->dev, gpt);
1133         pth_free (gpt);
1134         write_ok = ped_device_write (disk->dev, pth_raw,
1135                                      disk->dev->length - 1, 1);
1136         free (pth_raw);
1137         if (!write_ok)
1138                 goto error_free_ptes;
1139         if (!ped_device_write (disk->dev, ptes,
1140                                disk->dev->length - 1 - ptes_size / disk->dev->sector_size,
1141                                ptes_size / disk->dev->sector_size))
1142                 goto error_free_ptes;
1143
1144         free (ptes);
1145         return ped_device_sync (disk->dev);
1146
1147         free (pth_raw);
1148 error_free_ptes:
1149         free (ptes);
1150 error:
1151         return 0;
1152 }
1153 #endif /* !DISCOVER_ONLY */
1154
1155 static int
1156 add_metadata_part(PedDisk * disk, PedSector start, PedSector length)
1157 {
1158         PedPartition* part;
1159         PedConstraint* constraint_exact;
1160         PED_ASSERT(disk != NULL, return 0);
1161
1162         part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1163                                   start, start + length - 1);
1164         if (!part)
1165                 goto error;
1166
1167         constraint_exact = ped_constraint_exact (&part->geom);
1168         if (!ped_disk_add_partition (disk, part, constraint_exact))
1169                 goto error_destroy_constraint;
1170         ped_constraint_destroy (constraint_exact);
1171         return 1;
1172
1173 error_destroy_constraint:
1174         ped_constraint_destroy (constraint_exact);
1175         ped_partition_destroy (part);
1176 error:
1177         return 0;
1178 }
1179
1180 static PedPartition*
1181 gpt_partition_new (const PedDisk* disk,
1182                   PedPartitionType part_type, const PedFileSystemType* fs_type,
1183                   PedSector start, PedSector end)
1184 {
1185         PedPartition* part;
1186         GPTPartitionData* gpt_part_data;
1187
1188         part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1189         if (!part)
1190                 goto error;
1191
1192         if (part_type != 0)
1193                 return part;
1194
1195         gpt_part_data = part->disk_specific =
1196                 ped_malloc (sizeof (GPTPartitionData));
1197         if (!gpt_part_data)
1198                 goto error_free_part;
1199
1200         gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1201         gpt_part_data->lvm = 0;
1202         gpt_part_data->raid = 0;
1203         gpt_part_data->boot = 0;
1204         gpt_part_data->bios_grub = 0;
1205         gpt_part_data->hp_service = 0;
1206         gpt_part_data->hidden = 0;
1207         gpt_part_data->msftres = 0;
1208         uuid_generate ((unsigned char*) &gpt_part_data->uuid);
1209         swap_uuid_and_efi_guid((unsigned char*)(&gpt_part_data->uuid));
1210         memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1211         return part;
1212
1213 error_free_part:
1214         _ped_partition_free (part);
1215 error:
1216         return NULL;
1217 }
1218
1219 static PedPartition*
1220 gpt_partition_duplicate (const PedPartition* part)
1221 {
1222         PedPartition* result;
1223         GPTPartitionData* part_data = part->disk_specific;
1224         GPTPartitionData* result_data;
1225
1226         result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1227                                        part->geom.start, part->geom.end);
1228         if (!result)
1229                 goto error;
1230         result->num = part->num;
1231
1232         if (result->type != 0)
1233                 return result;
1234
1235         result_data = result->disk_specific =
1236                 ped_malloc (sizeof (GPTPartitionData));
1237         if (!result_data)
1238                 goto error_free_part;
1239
1240         result_data->type = part_data->type;
1241         result_data->uuid = part_data->uuid;
1242         strcpy (result_data->name, part_data->name);
1243         return result;
1244
1245 error_free_part:
1246         _ped_partition_free (result);
1247 error:
1248         return NULL;
1249 }
1250
1251 static void
1252 gpt_partition_destroy (PedPartition *part)
1253 {
1254         if (part->type == 0) {
1255                 PED_ASSERT (part->disk_specific != NULL, return);
1256                 free (part->disk_specific);
1257         }
1258
1259         _ped_partition_free (part);
1260 }
1261
1262 static int
1263 gpt_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
1264 {
1265         GPTPartitionData* gpt_part_data = part->disk_specific;
1266
1267         PED_ASSERT (gpt_part_data != NULL, return 0);
1268
1269         part->fs_type = fs_type;
1270
1271         if (gpt_part_data->lvm) {
1272                 gpt_part_data->type = PARTITION_LVM_GUID;
1273                 return 1;
1274         }
1275         if (gpt_part_data->raid) {
1276                 gpt_part_data->type = PARTITION_RAID_GUID;
1277                 return 1;
1278         }
1279         if (gpt_part_data->boot) {
1280                 gpt_part_data->type = PARTITION_SYSTEM_GUID;
1281                 return 1;
1282         }
1283         if (gpt_part_data->bios_grub) {
1284                 gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1285                 return 1;
1286         }
1287         if (gpt_part_data->hp_service) {
1288                 gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1289                 return 1;
1290         }
1291         if (gpt_part_data->msftres) {
1292                 gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1293                 return 1;
1294         }
1295
1296         if (fs_type) {
1297                 if (strncmp (fs_type->name, "fat", 3) == 0
1298                     || strcmp (fs_type->name, "ntfs") == 0) {
1299                         gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1300                         return 1;
1301                 }
1302                 if (strncmp (fs_type->name, "hfs", 3) == 0) {
1303                         gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1304                         return 1;
1305                 }
1306                 if (strstr (fs_type->name, "swap")) {
1307                         gpt_part_data->type = PARTITION_SWAP_GUID;
1308                         return 1;
1309                 }
1310         }
1311
1312         gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1313         return 1;
1314 }
1315
1316 /* Allocate metadata partitions for the GPTH and PTES */
1317 static int
1318 gpt_alloc_metadata (PedDisk * disk)
1319 {
1320         PedSector gptlength, pteslength = 0;
1321         GPTDiskData *gpt_disk_data;
1322
1323         PED_ASSERT(disk != NULL, return 0);
1324         PED_ASSERT(disk->dev != NULL, return 0);
1325         PED_ASSERT(disk->disk_specific != NULL, return 0);
1326         gpt_disk_data = disk->disk_specific;
1327
1328         gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1329                                       disk->dev->sector_size);
1330         pteslength = ped_div_round_up (gpt_disk_data->entry_count
1331                                        * sizeof (GuidPartitionEntry_t), disk->dev->sector_size);
1332
1333         /* metadata at the start of the disk includes the MBR */
1334         if (!add_metadata_part(disk, GPT_PMBR_LBA,
1335                                GPT_PMBR_SECTORS + gptlength + pteslength))
1336                 return 0;
1337
1338         /* metadata at the end of the disk */
1339         if (!add_metadata_part(disk, disk->dev->length - gptlength - pteslength,
1340                                gptlength + pteslength))
1341                 return 0;
1342
1343         return 1;
1344 }
1345
1346 /* Does nothing, as the read/new/destroy functions maintain part->num */
1347 static int
1348 gpt_partition_enumerate (PedPartition* part)
1349 {
1350         GPTDiskData* gpt_disk_data = part->disk->disk_specific;
1351         int i;
1352
1353         /* never change the partition numbers */
1354         if (part->num != -1)
1355                 return 1;
1356
1357         for (i = 1; i <= gpt_disk_data->entry_count; i++) {
1358                 if (!ped_disk_get_partition (part->disk, i)) {
1359                         part->num = i;
1360                         return 1;
1361                 }
1362         }
1363
1364         PED_ASSERT (0, return 0);
1365
1366         return 0; /* used if debug is disabled */
1367 }
1368
1369 static int
1370 gpt_partition_set_flag(PedPartition *part,
1371                        PedPartitionFlag flag,
1372                        int state)
1373 {
1374         GPTPartitionData *gpt_part_data;
1375         PED_ASSERT(part != NULL, return 0);
1376         PED_ASSERT(part->disk_specific != NULL, return 0);
1377         gpt_part_data = part->disk_specific;
1378
1379         switch (flag) {
1380         case PED_PARTITION_BOOT:
1381                 gpt_part_data->boot = state;
1382                 if (state)
1383                         gpt_part_data->raid
1384                                 = gpt_part_data->lvm
1385                                 = gpt_part_data->bios_grub
1386                                 = gpt_part_data->hp_service
1387                                 = gpt_part_data->msftres = 0;
1388                 return gpt_partition_set_system (part, part->fs_type);
1389         case PED_PARTITION_BIOS_GRUB:
1390                 gpt_part_data->bios_grub = state;
1391                 if (state)
1392                         gpt_part_data->raid
1393                                 = gpt_part_data->lvm
1394                                 = gpt_part_data->boot
1395                                 = gpt_part_data->hp_service
1396                                 = gpt_part_data->msftres = 0;
1397                 return gpt_partition_set_system (part, part->fs_type);
1398         case PED_PARTITION_RAID:
1399                 gpt_part_data->raid = state;
1400                 if (state)
1401                         gpt_part_data->boot
1402                                 = gpt_part_data->lvm
1403                                 = gpt_part_data->bios_grub
1404                                 = gpt_part_data->hp_service
1405                                 = gpt_part_data->msftres = 0;
1406                 return gpt_partition_set_system (part, part->fs_type);
1407         case PED_PARTITION_LVM:
1408                 gpt_part_data->lvm = state;
1409                 if (state)
1410                         gpt_part_data->boot
1411                                 = gpt_part_data->raid
1412                                 = gpt_part_data->bios_grub
1413                                 = gpt_part_data->hp_service
1414                                 = gpt_part_data->msftres = 0;
1415                 return gpt_partition_set_system (part, part->fs_type);
1416         case PED_PARTITION_HPSERVICE:
1417                 gpt_part_data->hp_service = state;
1418                 if (state)
1419                         gpt_part_data->boot
1420                                 = gpt_part_data->raid
1421                                 = gpt_part_data->lvm
1422                                 = gpt_part_data->bios_grub
1423                                 = gpt_part_data->msftres = 0;
1424                 return gpt_partition_set_system (part, part->fs_type);
1425         case PED_PARTITION_MSFT_RESERVED:
1426                 gpt_part_data->msftres = state;
1427                 if (state)
1428                         gpt_part_data->boot
1429                                 = gpt_part_data->raid
1430                                 = gpt_part_data->lvm
1431                                 = gpt_part_data->bios_grub
1432                                 = gpt_part_data->hp_service = 0;
1433                 return gpt_partition_set_system (part, part->fs_type);
1434         case PED_PARTITION_HIDDEN:
1435                 gpt_part_data->hidden = state;
1436                 return 1;
1437         case PED_PARTITION_SWAP:
1438         case PED_PARTITION_ROOT:
1439         case PED_PARTITION_LBA:
1440         default:
1441                 return 0;
1442         }
1443         return 1;
1444 }
1445
1446 static int
1447 gpt_partition_get_flag(const PedPartition *part, PedPartitionFlag flag)
1448 {
1449         GPTPartitionData *gpt_part_data;
1450         PED_ASSERT(part->disk_specific != NULL, return 0);
1451         gpt_part_data = part->disk_specific;
1452
1453         switch (flag) {
1454         case PED_PARTITION_RAID:
1455                 return gpt_part_data->raid;
1456         case PED_PARTITION_LVM:
1457                 return gpt_part_data->lvm;
1458         case PED_PARTITION_BOOT:
1459                 return gpt_part_data->boot;
1460         case PED_PARTITION_BIOS_GRUB:
1461                 return gpt_part_data->bios_grub;
1462         case PED_PARTITION_HPSERVICE:
1463                 return gpt_part_data->hp_service;
1464         case PED_PARTITION_MSFT_RESERVED:
1465                 return gpt_part_data->msftres;
1466         case PED_PARTITION_HIDDEN:
1467                        return gpt_part_data->hidden;
1468         case PED_PARTITION_SWAP:
1469         case PED_PARTITION_LBA:
1470         case PED_PARTITION_ROOT:
1471         default:
1472                 return 0;
1473         }
1474         return 0;
1475 }
1476
1477 static int
1478 gpt_partition_is_flag_available(const PedPartition * part,
1479                                 PedPartitionFlag flag)
1480 {
1481         switch (flag) {
1482         case PED_PARTITION_RAID:
1483         case PED_PARTITION_LVM:
1484         case PED_PARTITION_BOOT:
1485         case PED_PARTITION_BIOS_GRUB:
1486         case PED_PARTITION_HPSERVICE:
1487         case PED_PARTITION_MSFT_RESERVED:
1488         case PED_PARTITION_HIDDEN:
1489                 return 1;
1490         case PED_PARTITION_SWAP:
1491         case PED_PARTITION_ROOT:
1492         case PED_PARTITION_LBA:
1493         default:
1494                 return 0;
1495         }
1496         return 0;
1497 }
1498
1499 static void
1500 gpt_partition_set_name (PedPartition *part, const char *name)
1501 {
1502         GPTPartitionData *gpt_part_data = part->disk_specific;
1503
1504         strncpy (gpt_part_data->name, name, 36);
1505         gpt_part_data->name [36] = 0;
1506 }
1507
1508 static const char *
1509 gpt_partition_get_name (const PedPartition * part)
1510 {
1511         GPTPartitionData* gpt_part_data = part->disk_specific;
1512         return gpt_part_data->name;
1513 }
1514
1515 static int
1516 gpt_get_max_primary_partition_count (const PedDisk *disk)
1517 {
1518         const GPTDiskData* gpt_disk_data = disk->disk_specific;
1519         return gpt_disk_data->entry_count;
1520 }
1521
1522 /*
1523  * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1524  * According to the specs the first LBA (LBA0) is not relevant (it exists
1525  * to maintain compatibility).  on the second LBA(LBA1) gpt places the
1526  * header.  The header is as big as the block size.  After the header we
1527  * find the Entry array.  Each element of said array, describes each
1528  * partition.  One can have as much elements as can fit between the end of
1529  * the second LBA (where the header ends) and the FirstUsableLBA.
1530  * FirstUsableLBA is the first logical block that is used for contents
1531  * and is defined in header.
1532  *
1533  * /---------------------------------------------------\
1534  * | BLOCK0 | HEADER | Entry Array | First Usable LBA  |
1535  * |        | BLOCK1 |             |                   |
1536  * \---------------------------------------------------/
1537  *                  /              \
1538  *     /----------/                  \----------\
1539  *     /-----------------------------------------\
1540  *     |  E1  |  E2  |  E3  |...............| EN |
1541  *     \-----------------------------------------/
1542  *
1543  * The number of possible partitions or supported partitions is:
1544  * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1545  * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1546  */
1547 static bool
1548 gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1549 {
1550         GuidPartitionTableHeader_t *pth = NULL;
1551         uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1552
1553         if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1554             || ped_device_read (disk->dev, pth_raw,
1555                                 disk->dev->length, GPT_HEADER_SECTORS))
1556                 pth = pth_new_from_raw (disk->dev, pth_raw);
1557         free (pth_raw);
1558
1559         if (pth == NULL)
1560                 return false;
1561
1562         *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1563                   / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1564         pth_free (pth);
1565         return true;
1566 }
1567
1568 static PedConstraint*
1569 _non_metadata_constraint (const PedDisk* disk)
1570 {
1571         GPTDiskData* gpt_disk_data = disk->disk_specific;
1572
1573         return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1574 }
1575
1576 static int
1577 gpt_partition_align (PedPartition* part, const PedConstraint* constraint)
1578 {
1579         PED_ASSERT (part != NULL, return 0);
1580
1581         if (_ped_partition_attempt_align (part, constraint,
1582                         _non_metadata_constraint (part->disk)))
1583                 return 1;
1584
1585 #ifndef DISCOVER_ONLY
1586         ped_exception_throw (
1587                 PED_EXCEPTION_ERROR,
1588                 PED_EXCEPTION_CANCEL,
1589                 _("Unable to satisfy all constraints on the partition."));
1590 #endif
1591         return 0;
1592 }
1593
1594 static bool
1595 gpt_partition_check (const PedPartition* part)
1596 {
1597         return true;
1598 }
1599
1600 static PedDiskOps gpt_disk_ops = {
1601         probe:          gpt_probe,
1602 #ifndef DISCOVER_ONLY
1603         clobber:        gpt_clobber,
1604 #else
1605         clobber:        NULL,
1606 #endif
1607         alloc:          gpt_alloc,
1608         duplicate:      gpt_duplicate,
1609         free:           gpt_free,
1610         read:           gpt_read,
1611 #ifndef DISCOVER_ONLY
1612         write:          gpt_write,
1613 #else
1614         write:          NULL,
1615 #endif
1616         partition_new:                  gpt_partition_new,
1617         partition_duplicate:            gpt_partition_duplicate,
1618         partition_destroy:              gpt_partition_destroy,
1619         partition_set_system:           gpt_partition_set_system,
1620         partition_set_flag:             gpt_partition_set_flag,
1621         partition_get_flag:             gpt_partition_get_flag,
1622         partition_is_flag_available:    gpt_partition_is_flag_available,
1623         partition_set_name:             gpt_partition_set_name,
1624         partition_get_name:             gpt_partition_get_name,
1625         partition_align:                gpt_partition_align,
1626         partition_enumerate:            gpt_partition_enumerate,
1627         partition_check:                gpt_partition_check,
1628         alloc_metadata:                 gpt_alloc_metadata,
1629         get_max_primary_partition_count: gpt_get_max_primary_partition_count,
1630         get_max_supported_partition_count: gpt_get_max_supported_partition_count
1631 };
1632
1633 static PedDiskType gpt_disk_type = {
1634         next:           NULL,
1635         name:           "gpt",
1636         ops:            &gpt_disk_ops,
1637         features:       PED_DISK_TYPE_PARTITION_NAME
1638 };
1639
1640 void
1641 ped_disk_gpt_init()
1642 {
1643         PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1644         PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1645
1646         ped_disk_type_register (&gpt_disk_type);
1647 }
1648
1649 void
1650 ped_disk_gpt_done()
1651 {
1652         ped_disk_type_unregister (&gpt_disk_type);
1653 }