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