OSDN Git Service

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