1N/A/*
1N/A libparted - a library for manipulating disk partitions
1N/A
1N/A original version by Matt Domsch <Matt_Domsch@dell.com>
1N/A Disclaimed into the Public Domain
1N/A
1N/A Portions Copyright (C) 2001-2003, 2005-2010 Free Software Foundation, Inc.
1N/A
1N/A EFI GUID Partition Table handling
1N/A Per Intel EFI Specification v1.02
1N/A http://developer.intel.com/technology/efi/efi.htm
1N/A
1N/A This program is free software; you can redistribute it and/or modify
1N/A it under the terms of the GNU General Public License as published by
1N/A the Free Software Foundation; either version 3 of the License, or
1N/A (at your option) any later version.
1N/A
1N/A This program is distributed in the hope that it will be useful,
1N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A GNU General Public License for more details.
1N/A
1N/A You should have received a copy of the GNU General Public License
1N/A along with this program. If not, see <http://www.gnu.org/licenses/>.
1N/A*/
1N/A
1N/A#include <config.h>
1N/A
1N/A#include <parted/parted.h>
1N/A#include <parted/debug.h>
1N/A#include <parted/endian.h>
1N/A#include <parted/crc32.h>
1N/A#include <inttypes.h>
1N/A#include <stdio.h>
1N/A#include <sys/types.h>
1N/A#include <sys/ioctl.h>
1N/A#include <fcntl.h>
1N/A#include <unistd.h>
1N/A#include <uuid/uuid.h>
1N/A#include <stdbool.h>
1N/A#include <errno.h>
1N/A#include "xalloc.h"
1N/A
1N/A#include "pt-tools.h"
1N/A
1N/A#if ENABLE_NLS
1N/A# include <libintl.h>
1N/A# define _(String) gettext (String)
1N/A#else
1N/A# define _(String) (String)
1N/A#endif /* ENABLE_NLS */
1N/A
1N/A#define EFI_PMBR_OSTYPE_EFI 0xEE
1N/A#define MSDOS_MBR_SIGNATURE 0xaa55
1N/A
1N/A#define GPT_HEADER_SIGNATURE 0x5452415020494645LL
1N/A
1N/A/* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
1N/A * so some implementors got confused...
1N/A */
1N/A#define GPT_HEADER_REVISION_V1_02 0x00010200
1N/A#define GPT_HEADER_REVISION_V1_00 0x00010000
1N/A#define GPT_HEADER_REVISION_V0_99 0x00009900
1N/A
2N/A#ifndef MAX
2N/A#define MAX(x, y) ((x) > (y) ? (x) : (y))
2N/A#endif
2N/A
1N/A#ifdef __sun
1N/A#define __attribute__(X) /*nothing*/
1N/A#endif /* __sun */
1N/A
1N/Atypedef uint16_t efi_char16_t; /* UNICODE character */
1N/Atypedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
1N/Atypedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
1N/Atypedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
1N/Atypedef struct _PartitionRecord_t PartitionRecord_t;
1N/Atypedef struct _LegacyMBR_t LegacyMBR_t;
1N/Atypedef struct _GPTDiskData GPTDiskData;
1N/Atypedef struct
1N/A{
1N/A uint32_t time_low;
1N/A uint16_t time_mid;
1N/A uint16_t time_hi_and_version;
1N/A uint8_t clock_seq_hi_and_reserved;
1N/A uint8_t clock_seq_low;
1N/A uint8_t node[6];
1N/A} /* __attribute__ ((packed)) */ efi_guid_t;
1N/A/* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
1N/A * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
1N/A * data. It turns out we don't need it in this case, so it doesn't break
1N/A * anything :)
1N/A */
1N/A
1N/A#define UNUSED_ENTRY_GUID \
1N/A ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
1N/A { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
1N/A#define PARTITION_SYSTEM_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
1N/A PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
1N/A { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
1N/A#define PARTITION_BIOS_GRUB_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
1N/A PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
1N/A { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
1N/A#define LEGACY_MBR_PARTITION_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
1N/A PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
1N/A { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
1N/A#define PARTITION_MSFT_RESERVED_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
1N/A PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
1N/A { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
1N/A#define PARTITION_MSFT_RECOVERY \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0xDE94BBA4), PED_CPU_TO_LE16 (0x06D1), \
1N/A PED_CPU_TO_LE16 (0x4D40), 0xA1, 0x6A, \
1N/A { 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC }})
1N/A#define PARTITION_BASIC_DATA_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
1N/A PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
1N/A { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
1N/A#define PARTITION_RAID_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
1N/A PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
1N/A { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
1N/A#define PARTITION_SWAP_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
1N/A PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
1N/A { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
1N/A#define PARTITION_LVM_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
1N/A PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
1N/A { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
1N/A#define PARTITION_RESERVED_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
1N/A PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
1N/A { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
1N/A#define PARTITION_HPSERVICE_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
1N/A PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
1N/A { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
1N/A#define PARTITION_APPLE_HFS_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
1N/A PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
1N/A { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
1N/A#define PARTITION_APPLE_TV_RECOVERY_GUID \
1N/A ((efi_guid_t) { PED_CPU_TO_LE32 (0x5265636F), PED_CPU_TO_LE16 (0x7665), \
1N/A PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
1N/A { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
1N/A
1N/A#ifdef __sun
1N/A#pragma pack(1)
1N/A#endif
1N/Astruct __attribute__ ((packed)) _GuidPartitionTableHeader_t
1N/A{
1N/A uint64_t Signature;
1N/A uint32_t Revision;
1N/A uint32_t HeaderSize;
1N/A uint32_t HeaderCRC32;
1N/A uint32_t Reserved1;
1N/A uint64_t MyLBA;
1N/A uint64_t AlternateLBA;
1N/A uint64_t FirstUsableLBA;
1N/A uint64_t LastUsableLBA;
1N/A efi_guid_t DiskGUID;
1N/A uint64_t PartitionEntryLBA;
1N/A uint32_t NumberOfPartitionEntries;
1N/A uint32_t SizeOfPartitionEntry;
1N/A uint32_t PartitionEntryArrayCRC32;
1N/A uint8_t *Reserved2;
1N/A};
1N/A
1N/Astruct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
1N/A{
1N/A#if defined(__GNUC__) || defined(__sun) /* XXX narrow this down to !TinyCC */
1N/A uint64_t RequiredToFunction:1;
1N/A uint64_t Reserved:47;
1N/A uint64_t GuidSpecific:16;
1N/A#else
1N/A# warning "Using crippled partition entry type"
1N/A uint32_t RequiredToFunction:1;
1N/A uint32_t Reserved:32;
1N/A uint32_t LOST:5;
1N/A uint32_t GuidSpecific:16;
1N/A#endif
1N/A};
1N/A
1N/Astruct __attribute__ ((packed)) _GuidPartitionEntry_t
1N/A{
1N/A efi_guid_t PartitionTypeGuid;
1N/A efi_guid_t UniquePartitionGuid;
1N/A uint64_t StartingLBA;
1N/A uint64_t EndingLBA;
1N/A GuidPartitionEntryAttributes_t Attributes;
1N/A efi_char16_t PartitionName[72 / sizeof (efi_char16_t)];
1N/A};
1N/A#ifdef __sun
1N/A#pragma pack()
1N/A#endif
1N/A
1N/A#define GPT_PMBR_LBA 0
1N/A#define GPT_PMBR_SECTORS 1
1N/A#define GPT_PRIMARY_HEADER_LBA 1
1N/A#define GPT_HEADER_SECTORS 1
1N/A#define GPT_PRIMARY_PART_TABLE_LBA 2
1N/A
1N/A/*
1N/A These values are only defaults. The actual on-disk structures
1N/A may define different sizes, so use those unless creating a new GPT disk!
1N/A*/
1N/A
1N/A#define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
1N/A
1N/A/* Number of actual partition entries should be calculated as: */
1N/A#define GPT_DEFAULT_PARTITION_ENTRIES \
1N/A (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
1N/A sizeof(GuidPartitionEntry_t))
1N/A
1N/A#ifdef __sun
1N/A#pragma pack(1)
1N/A#endif
1N/Astruct __attribute__ ((packed)) _PartitionRecord_t
1N/A{
1N/A /* Not used by EFI firmware. Set to 0x80 to indicate that this
1N/A is the bootable legacy partition. */
1N/A uint8_t BootIndicator;
1N/A
1N/A /* Start of partition in CHS address, not used by EFI firmware. */
1N/A uint8_t StartHead;
1N/A
1N/A /* Start of partition in CHS address, not used by EFI firmware. */
1N/A uint8_t StartSector;
1N/A
1N/A /* Start of partition in CHS address, not used by EFI firmware. */
1N/A uint8_t StartTrack;
1N/A
1N/A /* OS type. A value of 0xEF defines an EFI system partition.
1N/A Other values are reserved for legacy operating systems, and
1N/A allocated independently of the EFI specification. */
1N/A uint8_t OSType;
1N/A
1N/A /* End of partition in CHS address, not used by EFI firmware. */
1N/A uint8_t EndHead;
1N/A
1N/A /* End of partition in CHS address, not used by EFI firmware. */
1N/A uint8_t EndSector;
1N/A
1N/A /* End of partition in CHS address, not used by EFI firmware. */
1N/A uint8_t EndTrack;
1N/A
1N/A /* Starting LBA address of the partition on the disk. Used by
1N/A EFI firmware to define the start of the partition. */
1N/A uint32_t StartingLBA;
1N/A
1N/A /* Size of partition in LBA. Used by EFI firmware to determine
1N/A the size of the partition. */
1N/A uint32_t SizeInLBA;
1N/A};
1N/A
1N/A/* Protected Master Boot Record & Legacy MBR share same structure */
1N/A/* Needs to be packed because the u16s force misalignment. */
1N/Astruct __attribute__ ((packed)) _LegacyMBR_t
1N/A{
1N/A uint8_t BootCode[440];
1N/A uint32_t UniqueMBRSignature;
1N/A uint16_t Unknown;
1N/A PartitionRecord_t PartitionRecord[4];
1N/A uint16_t Signature;
1N/A};
1N/A
1N/A/* uses libparted's disk_specific field in PedDisk, to store our info */
1N/Astruct __attribute__ ((packed)) _GPTDiskData
1N/A{
1N/A PedGeometry data_area;
1N/A int entry_count;
1N/A efi_guid_t uuid;
1N/A};
1N/A#ifdef __sun
1N/A#pragma pack()
1N/A#endif
1N/A
1N/A/* uses libparted's disk_specific field in PedPartition, to store our info */
1N/Atypedef struct _GPTPartitionData
1N/A{
1N/A efi_guid_t type;
1N/A efi_guid_t uuid;
1N/A char name[37];
1N/A int lvm;
1N/A int raid;
1N/A int boot;
1N/A int bios_grub;
1N/A int hp_service;
1N/A int hidden;
1N/A int msftres;
1N/A int atvrecv;
1N/A int msftrecv;
1N/A} GPTPartitionData;
1N/A
1N/Astatic PedDiskType gpt_disk_type;
1N/A
1N/Astatic inline uint32_t
1N/Apth_get_size (const PedDevice *dev)
1N/A{
1N/A return GPT_HEADER_SECTORS * dev->sector_size;
1N/A}
1N/A
1N/Astatic inline uint32_t
1N/Apth_get_size_static (const PedDevice *dev)
1N/A{
1N/A return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
1N/A}
1N/A
1N/Astatic inline uint32_t
1N/Apth_get_size_rsv2 (const PedDevice *dev)
1N/A{
1N/A return pth_get_size (dev) - pth_get_size_static (dev);
1N/A}
1N/A
1N/Astatic GuidPartitionTableHeader_t *
1N/Apth_new (const PedDevice *dev)
1N/A{
1N/A GuidPartitionTableHeader_t *pth =
1N/A ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
1N/A
1N/A pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
1N/A
1N/A return pth;
1N/A}
1N/A
1N/Astatic GuidPartitionTableHeader_t *
1N/Apth_new_zeroed (const PedDevice *dev)
1N/A{
1N/A GuidPartitionTableHeader_t *pth = pth_new (dev);
1N/A
1N/A memset (pth, 0, pth_get_size_static (dev));
1N/A memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
1N/A
1N/A return (pth);
1N/A}
1N/A
1N/Astatic GuidPartitionTableHeader_t *
1N/Apth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
1N/A{
1N/A GuidPartitionTableHeader_t *pth = pth_new (dev);
1N/A
1N/A PED_ASSERT (pth_raw != NULL, return 0);
1N/A
1N/A memcpy (pth, pth_raw, pth_get_size_static (dev));
1N/A memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
1N/A pth_get_size_rsv2 (dev));
1N/A
1N/A return pth;
1N/A}
1N/A
1N/Astatic void
1N/Apth_free (GuidPartitionTableHeader_t *pth)
1N/A{
1N/A if (pth == NULL)
1N/A return;
1N/A PED_ASSERT (pth->Reserved2 != NULL, return);
1N/A
1N/A free (pth->Reserved2);
1N/A free (pth);
1N/A}
1N/A
1N/Astatic uint8_t *
1N/Apth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
1N/A{
1N/A PED_ASSERT (pth != NULL, return 0);
1N/A PED_ASSERT (pth->Reserved2 != NULL, return 0);
1N/A
1N/A int size_static = pth_get_size_static (dev);
1N/A uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
1N/A if (pth_raw == NULL)
1N/A return NULL;
1N/A
1N/A memcpy (pth_raw, pth, size_static);
1N/A memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
1N/A
1N/A return pth_raw;
1N/A}
1N/A
1N/A/**
1N/A * swap_uuid_and_efi_guid() - converts between uuid formats
1N/A * @uuid - uuid_t in either format (converts it to the other)
1N/A *
1N/A * There are two different representations for Globally Unique Identifiers
1N/A * (GUIDs or UUIDs).
1N/A *
1N/A * The RFC specifies a UUID as a string of 16 bytes, essentially
1N/A * a big-endian array of char.
1N/A * Intel, in their EFI Specification, references the same RFC, but
1N/A * then defines a GUID as a structure of little-endian fields.
1N/A * Coincidentally, both structures have the same format when unparsed.
1N/A *
1N/A * When read from disk, EFI GUIDs are in struct of little endian format,
1N/A * and need to be converted to be treated as uuid_t in memory.
1N/A *
1N/A * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
1N/A *
1N/A * Blame Intel.
1N/A */
1N/Astatic void
1N/Aswap_uuid_and_efi_guid (uuid_t uuid)
1N/A{
1N/A efi_guid_t *guid = (efi_guid_t *) uuid;
1N/A
1N/A PED_ASSERT (uuid != NULL, return);
1N/A guid->time_low = PED_SWAP32 (guid->time_low);
1N/A guid->time_mid = PED_SWAP16 (guid->time_mid);
1N/A guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
1N/A}
1N/A
1N/A/* returns the EFI-style CRC32 value for buf
1N/A * This function uses the crc32 function by Gary S. Brown,
1N/A * but seeds the function with ~0, and xor's with ~0 at the end.
1N/A */
1N/Astatic inline uint32_t
1N/Aefi_crc32 (const void *buf, unsigned long len)
1N/A{
1N/A return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
1N/A}
1N/A
1N/A/* Compute the crc32 checksum of the partition table header
1N/A and store it in *CRC32. Return 0 upon success. Return 1
1N/A upon failure to allocate space. */
1N/Astatic int
1N/Apth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth,
1N/A uint32_t *crc32)
1N/A{
1N/A PED_ASSERT (dev != NULL, return 0);
1N/A PED_ASSERT (pth != NULL, return 0);
1N/A
1N/A uint8_t *pth_raw = pth_get_raw (dev, pth);
1N/A if (pth_raw == NULL)
1N/A return 1;
1N/A
1N/A *crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
1N/A free (pth_raw);
1N/A
1N/A return 0;
1N/A}
1N/A
1N/Astatic inline int
1N/Aguid_cmp (efi_guid_t left, efi_guid_t right)
1N/A{
1N/A return memcmp (&left, &right, sizeof (efi_guid_t));
1N/A}
1N/A
1N/A/* checks if 'mbr' is a protective MBR partition table */
1N/Astatic inline int
1N/A_pmbr_is_valid (const LegacyMBR_t *mbr)
1N/A{
1N/A int i;
1N/A
1N/A PED_ASSERT (mbr != NULL, return 0);
1N/A
1N/A if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
1N/A return 0;
1N/A for (i = 0; i < 4; i++)
1N/A {
1N/A if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
1N/A return 1;
1N/A }
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/Agpt_probe (const PedDevice *dev)
1N/A{
1N/A GuidPartitionTableHeader_t *gpt = NULL;
1N/A int gpt_sig_found = 0;
1N/A
1N/A PED_ASSERT (dev != NULL, return 0);
1N/A
1N/A if (dev->length <= 1)
1N/A return 0;
1N/A
1N/A void *pth_raw = ped_malloc (pth_get_size (dev));
1N/A if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
1N/A || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
1N/A {
1N/A gpt = pth_new_from_raw (dev, pth_raw);
1N/A if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
1N/A gpt_sig_found = 1;
1N/A }
1N/A
1N/A free (pth_raw);
1N/A
1N/A pth_free (gpt);
1N/A
1N/A if (!gpt_sig_found)
1N/A return 0;
1N/A
1N/A void *label;
1N/A if (!ptt_read_sector (dev, 0, &label))
1N/A return 0;
1N/A
1N/A int ok = 1;
1N/A if (!_pmbr_is_valid ((const LegacyMBR_t *) label))
1N/A {
1N/A int ex_status = ped_exception_throw
1N/A (PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_YES_NO,
1N/A _("%s contains GPT signatures, indicating that it has "
1N/A "a GPT table. However, it does not have a valid "
1N/A "fake msdos partition table, as it should. Perhaps "
1N/A "it was corrupted -- possibly by a program that "
1N/A "doesn't understand GPT partition tables. Or "
1N/A "perhaps you deleted the GPT table, and are now "
1N/A "using an msdos partition table. Is this a GPT "
1N/A "partition table?"),
1N/A dev->path);
1N/A if (ex_status == PED_EXCEPTION_NO)
1N/A ok = 0;
1N/A }
1N/A
1N/A free (label);
1N/A return ok;
1N/A}
1N/A
1N/Astatic PedDisk *
1N/Agpt_alloc (const PedDevice *dev)
1N/A{
1N/A PedDisk *disk;
1N/A GPTDiskData *gpt_disk_data;
1N/A PedSector data_start, data_end;
1N/A
1N/A disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
1N/A if (!disk)
1N/A goto error;
1N/A disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
1N/A if (!disk->disk_specific)
1N/A goto error_free_disk;
1N/A
1N/A data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
1N/A data_end = dev->length - 2
1N/A - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
1N/A ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
1N/A data_end - data_start + 1);
1N/A gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
1N/A uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
1N/A swap_uuid_and_efi_guid ((unsigned char *) (&gpt_disk_data->uuid));
1N/A return disk;
1N/A
1N/Aerror_free_disk:
1N/A free (disk);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic PedDisk *
1N/Agpt_duplicate (const PedDisk *disk)
1N/A{
1N/A PedDisk *new_disk;
1N/A GPTDiskData *new_disk_data;
1N/A GPTDiskData *old_disk_data;
1N/A
1N/A new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
1N/A if (!new_disk)
1N/A return NULL;
1N/A
1N/A old_disk_data = disk->disk_specific;
1N/A new_disk_data = new_disk->disk_specific;
1N/A
1N/A ped_geometry_init (&new_disk_data->data_area, disk->dev,
1N/A old_disk_data->data_area.start,
1N/A old_disk_data->data_area.length);
1N/A new_disk_data->entry_count = old_disk_data->entry_count;
1N/A new_disk_data->uuid = old_disk_data->uuid;
1N/A return new_disk;
1N/A}
1N/A
1N/Astatic void
1N/Agpt_free (PedDisk *disk)
1N/A{
1N/A ped_disk_delete_all (disk);
1N/A free (disk->disk_specific);
1N/A _ped_disk_free (disk);
1N/A}
1N/A
1N/A/* Given GUID Partition table header, GPT, read its partition array
1N/A entries from DISK into malloc'd storage. Set *PTES_BYTES to the
1N/A number of bytes required. Upon success, return a pointer to the
1N/A resulting buffer. Otherwise, set errno and return NULL. */
1N/Astatic void *
1N/Agpt_read_PE_array (PedDisk const *disk, GuidPartitionTableHeader_t const *gpt,
1N/A size_t *ptes_bytes)
1N/A{
1N/A uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
2N/A *ptes_bytes = p_ent_size * PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
1N/A size_t ptes_sectors = ped_div_round_up (*ptes_bytes,
1N/A disk->dev->sector_size);
1N/A
1N/A if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
1N/A {
1N/A errno = ENOMEM;
1N/A return NULL;
1N/A }
1N/A void *ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
1N/A if (ptes == NULL)
1N/A return NULL;
1N/A
1N/A if (!ped_device_read (disk->dev, ptes,
1N/A PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
1N/A {
1N/A int saved_errno = errno;
1N/A free (ptes);
1N/A errno = saved_errno;
1N/A return NULL;
1N/A }
1N/A
1N/A return ptes;
1N/A}
1N/A
1N/Astatic int
1N/Acheck_PE_array_CRC (PedDisk const *disk,
1N/A GuidPartitionTableHeader_t const *gpt, bool *valid)
1N/A{
1N/A size_t ptes_bytes;
1N/A void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
1N/A if (ptes == NULL)
1N/A return 1;
1N/A
1N/A uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
1N/A *valid = (ptes_crc == PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32));
1N/A free (ptes);
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/A_header_is_valid (PedDisk const *disk, GuidPartitionTableHeader_t *gpt,
1N/A PedSector my_lba)
1N/A{
1N/A uint32_t crc, origcrc;
1N/A PedDevice const *dev = disk->dev;
1N/A
1N/A if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
1N/A return 0;
1N/A /*
1N/A * "While the GUID Partition Table Header's size may increase
1N/A * in the future it cannot span more than one block on the
1N/A * device." EFI Specification, version 1.10, 11.2.2.1
1N/A */
1N/A if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
1N/A || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
1N/A return 0;
1N/A
1N/A /* The SizeOfPartitionEntry must be a multiple of 8 and
1N/A no smaller than the size of the PartitionEntry structure.
1N/A We also require that be no larger than 1/16th of UINT32_MAX,
1N/A as an additional sanity check. */
1N/A uint32_t sope = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
1N/A if (sope % 8 != 0
1N/A || sope < sizeof (GuidPartitionEntry_t) || (UINT32_MAX >> 4) < sope)
1N/A return 0;
1N/A
1N/A if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
1N/A return 0;
1N/A
1N/A PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
1N/A /* The backup table's AlternateLBA must be 1. */
1N/A if (my_lba != 1 && alt_lba != 1)
1N/A return 0;
1N/A
1N/A /* The alt_lba must never be the same as my_lba. */
1N/A if (alt_lba == my_lba)
1N/A return 0;
1N/A
1N/A bool crc_match;
1N/A if (check_PE_array_CRC (disk, gpt, &crc_match) != 0 || !crc_match)
1N/A return 0;
1N/A
1N/A origcrc = gpt->HeaderCRC32;
1N/A gpt->HeaderCRC32 = 0;
1N/A if (pth_crc32 (dev, gpt, &crc) != 0)
1N/A return 0;
1N/A gpt->HeaderCRC32 = origcrc;
1N/A
1N/A return crc == PED_LE32_TO_CPU (origcrc);
1N/A}
1N/A
1N/Astatic int
1N/A_parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
1N/A int *update_needed)
1N/A{
1N/A GPTDiskData *gpt_disk_data = disk->disk_specific;
1N/A PedSector first_usable;
1N/A PedSector last_usable;
1N/A PedSector last_usable_if_grown, last_usable_min_default;
1N/A static int asked_already;
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
1N/A {
1N/A if (ped_exception_throw
1N/A (PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_IGNORE_CANCEL,
1N/A _("The format of the GPT partition table is version "
1N/A "%x, which is newer than what Parted can "
1N/A "recognise. Please tell us! bug-parted@gnu.org"),
1N/A PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
1N/A return 0;
1N/A }
1N/A#endif
1N/A
1N/A first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
1N/A last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
1N/A
1N/A /* Need to check whether the volume has grown, the LastUsableLBA is
1N/A normally set to disk->dev->length - 2 - ptes_size (at least for parted
1N/A created volumes), where ptes_size is the number of entries *
1N/A size of each entry / sector size or 16k / sector size, whatever the greater.
1N/A If the volume has grown, offer the user the chance to use the new
1N/A space or continue with the current usable area. Only ask once per
1N/A parted invocation. */
1N/A
1N/A last_usable_if_grown
1N/A = (disk->dev->length - 2 -
1N/A ((PedSector) (PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries)) *
1N/A (PedSector) (PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry)) /
1N/A disk->dev->sector_size));
1N/A
1N/A last_usable_min_default = disk->dev->length - 2 -
1N/A GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / disk->dev->sector_size;
1N/A
1N/A if (last_usable_if_grown > last_usable_min_default)
1N/A {
1N/A last_usable_if_grown = last_usable_min_default;
1N/A }
1N/A
1N/A PED_ASSERT (last_usable > first_usable, return 0);
1N/A PED_ASSERT (last_usable <= disk->dev->length, return 0);
1N/A
1N/A PED_ASSERT (last_usable_if_grown > first_usable, return 0);
1N/A PED_ASSERT (last_usable_if_grown <= disk->dev->length, return 0);
1N/A
1N/A if (!asked_already && last_usable < last_usable_if_grown)
1N/A {
1N/A
1N/A PedExceptionOption q;
1N/A
1N/A q = ped_exception_throw
1N/A (PED_EXCEPTION_WARNING,
1N/A PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
1N/A _("Not all of the space available to %s appears "
1N/A "to be used, you can fix the GPT to use all of the "
1N/A "space (an extra %llu blocks) or continue with the "
1N/A "current setting? "), disk->dev->path,
1N/A (uint64_t) (last_usable_if_grown - last_usable));
1N/A
1N/A if (q == PED_EXCEPTION_FIX)
1N/A {
1N/A last_usable = last_usable_if_grown;
1N/A *update_needed = 1;
1N/A }
1N/A else if (q != PED_EXCEPTION_UNHANDLED)
1N/A {
1N/A asked_already = 1;
1N/A }
1N/A }
1N/A
1N/A ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
1N/A first_usable, last_usable - first_usable + 1);
1N/A
1N/A gpt_disk_data->entry_count
1N/A = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
1N/A PED_ASSERT (gpt_disk_data->entry_count > 0, return 0);
1N/A PED_ASSERT (gpt_disk_data->entry_count <= 8192, return 0);
1N/A
1N/A gpt_disk_data->uuid = gpt->DiskGUID;
1N/A
1N/A return 1;
1N/A}
1N/A
1N/Astatic PedPartition *
1N/A_parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
1N/A{
1N/A PedPartition *part;
1N/A GPTPartitionData *gpt_part_data;
1N/A unsigned int i;
1N/A
1N/A part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
1N/A PED_LE64_TO_CPU (pte->StartingLBA),
1N/A PED_LE64_TO_CPU (pte->EndingLBA));
1N/A if (!part)
1N/A return NULL;
1N/A
1N/A gpt_part_data = part->disk_specific;
1N/A gpt_part_data->type = pte->PartitionTypeGuid;
1N/A gpt_part_data->uuid = pte->UniquePartitionGuid;
1N/A for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1N/A gpt_part_data->name[i] =
1N/A (efi_char16_t) PED_LE16_TO_CPU ((uint16_t) pte->PartitionName[i]);
1N/A gpt_part_data->name[i] = 0;
1N/A
1N/A gpt_part_data->lvm = gpt_part_data->raid
1N/A = gpt_part_data->boot = gpt_part_data->hp_service
1N/A = gpt_part_data->hidden = gpt_part_data->msftres
1N/A = gpt_part_data->msftrecv
1N/A = gpt_part_data->bios_grub = gpt_part_data->atvrecv = 0;
1N/A
1N/A if (pte->Attributes.RequiredToFunction & 0x1)
1N/A gpt_part_data->hidden = 1;
1N/A
1N/A if (!guid_cmp (gpt_part_data->type, PARTITION_SYSTEM_GUID))
1N/A gpt_part_data->boot = 1;
1N/A else if (!guid_cmp (gpt_part_data->type, PARTITION_BIOS_GRUB_GUID))
1N/A gpt_part_data->bios_grub = 1;
1N/A else if (!guid_cmp (gpt_part_data->type, PARTITION_RAID_GUID))
1N/A gpt_part_data->raid = 1;
1N/A else if (!guid_cmp (gpt_part_data->type, PARTITION_LVM_GUID))
1N/A gpt_part_data->lvm = 1;
1N/A else if (!guid_cmp (gpt_part_data->type, PARTITION_HPSERVICE_GUID))
1N/A gpt_part_data->hp_service = 1;
1N/A else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RESERVED_GUID))
1N/A gpt_part_data->msftres = 1;
1N/A else if (!guid_cmp (gpt_part_data->type, PARTITION_MSFT_RECOVERY))
1N/A gpt_part_data->msftrecv = 1;
1N/A else if (!guid_cmp (gpt_part_data->type, PARTITION_APPLE_TV_RECOVERY_GUID))
1N/A gpt_part_data->atvrecv = 1;
1N/A
1N/A return part;
1N/A}
1N/A
1N/A/* Read the primary GPT at sector 1 of DEV.
1N/A Verify its CRC and that of its partition entry array.
1N/A If they are valid, read the backup GPT specified by AlternateLBA.
1N/A If not, read the backup GPT in the last sector of the disk.
1N/A Return 1 if any read fails.
1N/A Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
1N/A Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
1N/A If we've set *BACKUP_GPT to non-NULL, set *BACKUP_LBA to the sector
1N/A number in which it was found. */
1N/Astatic int
1N/Agpt_read_headers (PedDisk const *disk,
1N/A GuidPartitionTableHeader_t **primary_gpt,
1N/A GuidPartitionTableHeader_t **backup_gpt,
1N/A PedSector *backup_sector_num_p)
1N/A{
1N/A *primary_gpt = NULL;
1N/A *backup_gpt = NULL;
1N/A PedDevice const *dev = disk->dev;
1N/A
1N/A void *s1;
1N/A if (!ptt_read_sector (dev, 1, &s1))
1N/A return 1;
1N/A
1N/A GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
1N/A free (s1);
1N/A if (t == NULL)
1N/A return 1;
1N/A GuidPartitionTableHeader_t *pri = t;
1N/A
1N/A bool valid_primary = _header_is_valid (disk, pri, 1);
1N/A if (valid_primary)
1N/A *primary_gpt = pri;
1N/A else
1N/A pth_free (pri);
1N/A
1N/A PedSector backup_sector_num =
1N/A (valid_primary
1N/A ? PED_LE64_TO_CPU (pri->AlternateLBA)
1N/A : dev->length - 1);
1N/A
1N/A void *s_bak;
1N/A if (!ptt_read_sector (dev, backup_sector_num, &s_bak))
1N/A return 1;
1N/A t = pth_new_from_raw (dev, s_bak);
1N/A free (s_bak);
1N/A if (t == NULL)
1N/A return 1;
1N/A
1N/A GuidPartitionTableHeader_t *bak = t;
1N/A if (_header_is_valid (disk, bak, backup_sector_num))
1N/A {
1N/A *backup_gpt = bak;
1N/A *backup_sector_num_p = backup_sector_num;
1N/A }
1N/A else
1N/A pth_free (bak);
1N/A
1N/A return 0;
1N/A}
1N/A
1N/A/************************************************************
1N/A * Intel is changing the EFI Spec. (after v1.02) to say that a
1N/A * disk is considered to have a GPT label only if the GPT
1N/A * structures are correct, and the MBR is actually a Protective
1N/A * MBR (has one 0xEE type partition).
1N/A * Problem occurs when a GPT-partitioned disk is then
1N/A * edited with a legacy (non-GPT-aware) application, such as
1N/A * fdisk (which doesn't generally erase the PGPT or AGPT).
1N/A * How should such a disk get handled? As a GPT disk (throwing
1N/A * away the fdisk changes), or as an MSDOS disk (throwing away
1N/A * the GPT information). Previously, I've taken the GPT-is-right,
1N/A * MBR is wrong, approach, to stay consistent with the EFI Spec.
1N/A * Intel disagrees, saying the disk should then be treated
1N/A * as having a msdos label, not a GPT label. If this is true,
1N/A * then what's the point of having an AGPT, since if the PGPT
1N/A * is screwed up, likely the PMBR is too, and the PMBR becomes
1N/A * a single point of failure.
1N/A * So, in the Linux kernel, I'm going to test for PMBR, and
1N/A * warn if it's not there, and treat the disk as MSDOS, with a note
1N/A * for users to use Parted to "fix up" their disk if they
1N/A * really want it to be considered GPT.
1N/A ************************************************************/
1N/Astatic int
1N/Agpt_read (PedDisk *disk)
1N/A{
1N/A GPTDiskData *gpt_disk_data = disk->disk_specific;
1N/A int i;
1N/A#ifndef DISCOVER_ONLY
1N/A int write_back = 0;
1N/A#endif
1N/A
1N/A ped_disk_delete_all (disk);
1N/A
1N/A /* motivation: let the user decide about the pmbr... during
1N/A ped_disk_probe(), they probably didn't get a choice... */
1N/A if (!gpt_probe (disk->dev))
1N/A goto error;
1N/A
1N/A GuidPartitionTableHeader_t *gpt = NULL;
1N/A GuidPartitionTableHeader_t *primary_gpt;
1N/A GuidPartitionTableHeader_t *backup_gpt;
1N/A PedSector backup_sector_num;
1N/A int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
1N/A &backup_sector_num);
1N/A if (read_failure)
1N/A {
1N/A /* This includes the case in which there used to be a GPT partition
1N/A table here, with an alternate LBA that extended beyond the current
1N/A end-of-device. It's treated as a non-match. */
1N/A
1N/A /* Another possibility:
1N/A The primary header is ok, but backup is corrupt.
1N/A In the UEFI spec, this means the primary GUID table
1N/A is officially invalid. */
1N/A pth_free (backup_gpt);
1N/A pth_free (primary_gpt);
1N/A return 0;
1N/A }
1N/A
1N/A if (primary_gpt && backup_gpt)
1N/A {
1N/A /* Both are valid. */
1N/A#ifndef DISCOVER_ONLY
1N/A if (PED_LE64_TO_CPU (primary_gpt->AlternateLBA) < disk->dev->length - 1)
1N/A {
1N/A switch (ped_exception_throw
1N/A (PED_EXCEPTION_ERROR,
1N/A (PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL
1N/A | PED_EXCEPTION_IGNORE),
1N/A _("The backup GPT table is not at the end of the disk, as it "
1N/A "should be. This might mean that another operating system "
1N/A "believes the disk is smaller. Fix, by moving the backup "
1N/A "to the end (and removing the old backup)?")))
1N/A {
1N/A case PED_EXCEPTION_CANCEL:
1N/A goto error_free_gpt;
1N/A case PED_EXCEPTION_FIX:
1N/A ptt_clear_sectors (disk->dev,
1N/A PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
1N/A write_back = 1;
1N/A break;
1N/A default:
1N/A break;
1N/A }
1N/A }
1N/A#endif /* !DISCOVER_ONLY */
1N/A gpt = primary_gpt;
1N/A pth_free (backup_gpt);
1N/A }
1N/A else if (!primary_gpt && !backup_gpt)
1N/A {
1N/A /* Both are corrupt. */
1N/A ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
1N/A _("Both the primary and backup GPT tables "
1N/A "are corrupt. Try making a fresh table, "
1N/A "and using Parted's rescue feature to "
1N/A "recover partitions."));
1N/A goto error;
1N/A }
1N/A else if (primary_gpt && !backup_gpt)
1N/A {
1N/A /* The primary header is ok, but backup is corrupt. */
1N/A if (ped_exception_throw
1N/A (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
1N/A _("The backup GPT table is corrupt, but the "
1N/A "primary appears OK, so that will be used."))
1N/A == PED_EXCEPTION_CANCEL)
1N/A goto error_free_gpt;
1N/A
1N/A gpt = primary_gpt;
1N/A }
1N/A else /* !primary_gpt && backup_gpt */
1N/A {
1N/A /* primary GPT corrupt, backup is ok. */
1N/A if (ped_exception_throw
1N/A (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
1N/A _("The primary GPT table is corrupt, but the "
1N/A "backup appears OK, so that will be used."))
1N/A == PED_EXCEPTION_CANCEL)
1N/A goto error_free_gpt;
1N/A
1N/A gpt = backup_gpt;
1N/A }
1N/A backup_gpt = NULL;
1N/A primary_gpt = NULL;
1N/A
1N/A if (!_parse_header (disk, gpt, &write_back))
1N/A goto error_free_gpt;
1N/A
1N/A size_t ptes_bytes;
1N/A void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
1N/A if (ptes == NULL)
1N/A goto error_free_gpt;
1N/A
1N/A uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
1N/A if (ptes_crc != PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32))
1N/A {
1N/A ped_exception_throw
1N/A (PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("primary partition table array CRC mismatch"));
1N/A goto error_free_ptes;
1N/A }
1N/A
1N/A uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
1N/A for (i = 0; i < gpt_disk_data->entry_count; i++)
1N/A {
1N/A GuidPartitionEntry_t *pte
1N/A = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
1N/A PedPartition *part;
1N/A
1N/A if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
1N/A continue;
1N/A
1N/A part = _parse_part_entry (disk, pte);
1N/A if (!part)
1N/A goto error_delete_all;
1N/A
1N/A part->fs_type = ped_file_system_probe (&part->geom);
1N/A part->num = i + 1;
1N/A
1N/A PedConstraint *constraint_exact = ped_constraint_exact (&part->geom);
1N/A if (!ped_disk_add_partition (disk, part, constraint_exact))
1N/A {
1N/A ped_constraint_destroy (constraint_exact);
1N/A ped_partition_destroy (part);
1N/A goto error_delete_all;
1N/A }
1N/A ped_constraint_destroy (constraint_exact);
1N/A }
1N/A free (ptes);
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A if (write_back)
1N/A ped_disk_commit_to_dev (disk);
1N/A#endif
1N/A
1N/A pth_free (gpt);
1N/A return 1;
1N/A
1N/Aerror_delete_all:
1N/A ped_disk_delete_all (disk);
1N/Aerror_free_ptes:
1N/A free (ptes);
1N/Aerror_free_gpt:
1N/A pth_free (primary_gpt);
1N/A pth_free (backup_gpt);
1N/A pth_free (gpt);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A/* Write the protective MBR (to keep DOS happy) */
1N/Astatic int
1N/A_write_pmbr (PedDevice *dev)
1N/A{
1N/A /* The UEFI spec is not clear about what to do with the following
1N/A elements of the Protective MBR (pmbr): BootCode (0-440B),
1N/A UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
1N/A With this in mind, we try not to modify these elements. */
1N/A void *s0;
1N/A if (!ptt_read_sector (dev, 0, &s0))
1N/A return 0;
1N/A LegacyMBR_t *pmbr = s0;
1N/A
1N/A /* Zero out the legacy partitions. */
1N/A memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
1N/A
1N/A pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
1N/A pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
1N/A pmbr->PartitionRecord[0].StartSector = 1;
1N/A pmbr->PartitionRecord[0].EndHead = 0xFE;
1N/A pmbr->PartitionRecord[0].EndSector = 0xFF;
1N/A pmbr->PartitionRecord[0].EndTrack = 0xFF;
1N/A pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
1N/A if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
1N/A pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
1N/A else
1N/A pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
1N/A
1N/A int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
1N/A GPT_PMBR_SECTORS);
1N/A free (s0);
1N/A return write_ok;
1N/A}
1N/A
1N/Astatic int
1N/A_generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
1N/A GuidPartitionTableHeader_t **gpt_p)
1N/A{
1N/A GPTDiskData *gpt_disk_data = disk->disk_specific;
1N/A GuidPartitionTableHeader_t *gpt;
1N/A
1N/A *gpt_p = pth_new_zeroed (disk->dev);
1N/A
1N/A gpt = *gpt_p;
1N/A
1N/A gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
1N/A gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
1N/A
1N/A /* per 1.00 spec */
1N/A gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
1N/A gpt->HeaderCRC32 = 0;
1N/A gpt->Reserved1 = 0;
1N/A
1N/A if (alternate)
1N/A {
2N/A int writing_entry_count = MAX(gpt_disk_data->entry_count,
2N/A GPT_DEFAULT_PARTITION_ENTRIES);
2N/A PedSector ptes_size = writing_entry_count
1N/A * sizeof (GuidPartitionEntry_t) / disk->dev->sector_size;
1N/A
1N/A gpt->MyLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1N/A gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
1N/A gpt->PartitionEntryLBA
1N/A = PED_CPU_TO_LE64 (disk->dev->length - 1 - ptes_size);
1N/A }
1N/A else
1N/A {
1N/A gpt->MyLBA = PED_CPU_TO_LE64 (1);
1N/A gpt->AlternateLBA = PED_CPU_TO_LE64 (disk->dev->length - 1);
1N/A gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
1N/A }
1N/A
1N/A gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
1N/A gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
1N/A gpt->DiskGUID = gpt_disk_data->uuid;
1N/A gpt->NumberOfPartitionEntries
1N/A = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
1N/A gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
1N/A gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
1N/A
1N/A uint32_t crc;
1N/A if (pth_crc32 (disk->dev, gpt, &crc) != 0)
1N/A return 1;
1N/A
1N/A gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
1N/A return 0;
1N/A}
1N/A
1N/Astatic void
1N/A_partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
1N/A{
1N/A GPTPartitionData *gpt_part_data = part->disk_specific;
1N/A unsigned int i;
1N/A
1N/A PED_ASSERT (gpt_part_data != NULL, return);
1N/A
1N/A pte->PartitionTypeGuid = gpt_part_data->type;
1N/A pte->UniquePartitionGuid = gpt_part_data->uuid;
1N/A pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
1N/A pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
1N/A memset (&pte->Attributes, 0, sizeof (GuidPartitionEntryAttributes_t));
1N/A
1N/A if (gpt_part_data->hidden)
1N/A pte->Attributes.RequiredToFunction = 1;
1N/A
1N/A for (i = 0; i < 72 / sizeof (efi_char16_t); i++)
1N/A pte->PartitionName[i]
1N/A = (efi_char16_t) PED_CPU_TO_LE16 ((uint16_t) gpt_part_data->name[i]);
1N/A}
1N/A
1N/Astatic int
1N/Agpt_write (const PedDisk *disk)
1N/A{
1N/A GPTDiskData *gpt_disk_data;
1N/A GuidPartitionEntry_t *ptes;
1N/A uint32_t ptes_crc;
1N/A uint8_t *pth_raw;
1N/A GuidPartitionTableHeader_t *gpt;
1N/A PedPartition *part;
1N/A int ptes_size;
1N/A
1N/A PED_ASSERT (disk != NULL, goto error);
1N/A PED_ASSERT (disk->dev != NULL, goto error);
1N/A PED_ASSERT (disk->disk_specific != NULL, goto error);
1N/A
2N/A /*
2N/A * Solaris 11 has a bug. It creates only 9 partition table entries and
2N/A * the CRC covers only them. But it allocates blocks for and writes out
2N/A * 128 PTEs, as is required by the spec.
2N/A */
1N/A gpt_disk_data = disk->disk_specific;
2N/A int crc_ptes_size = sizeof (GuidPartitionEntry_t) *
2N/A gpt_disk_data->entry_count;
2N/A int writing_entry_count = MAX(gpt_disk_data->entry_count,
2N/A GPT_DEFAULT_PARTITION_ENTRIES);
1N/A
2N/A ptes_size = sizeof (GuidPartitionEntry_t) * writing_entry_count;
1N/A ptes = (GuidPartitionEntry_t *) ped_malloc (ptes_size);
1N/A if (!ptes)
1N/A goto error;
1N/A memset (ptes, 0, ptes_size);
1N/A for (part = ped_disk_next_partition (disk, NULL); part;
1N/A part = ped_disk_next_partition (disk, part))
1N/A {
1N/A if (part->type != 0)
1N/A continue;
1N/A _partition_generate_part_entry (part, &ptes[part->num - 1]);
1N/A }
1N/A
2N/A ptes_crc = efi_crc32 (ptes, crc_ptes_size);
1N/A
1N/A /* Write protective MBR */
1N/A if (!_write_pmbr (disk->dev))
1N/A goto error_free_ptes;
1N/A
1N/A /* Write PTH and PTEs */
1N/A /* FIXME: Caution: this code is nearly identical to what's just below. */
1N/A if (_generate_header (disk, 0, ptes_crc, &gpt) != 0)
1N/A goto error_free_ptes;
1N/A pth_raw = pth_get_raw (disk->dev, gpt);
1N/A pth_free (gpt);
1N/A if (pth_raw == NULL)
1N/A goto error_free_ptes;
1N/A int write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
1N/A free (pth_raw);
1N/A if (!write_ok)
1N/A goto error_free_ptes;
1N/A if (!ped_device_write (disk->dev, ptes, 2,
1N/A ptes_size / disk->dev->sector_size))
1N/A goto error_free_ptes;
1N/A
1N/A /* Write Alternate PTH & PTEs */
1N/A /* FIXME: Caution: this code is nearly identical to what's just above. */
1N/A if (_generate_header (disk, 1, ptes_crc, &gpt) != 0)
1N/A goto error_free_ptes;
1N/A pth_raw = pth_get_raw (disk->dev, gpt);
1N/A pth_free (gpt);
1N/A if (pth_raw == NULL)
1N/A goto error_free_ptes;
1N/A write_ok = ped_device_write (disk->dev, pth_raw, disk->dev->length - 1, 1);
1N/A free (pth_raw);
1N/A if (!write_ok)
1N/A goto error_free_ptes;
1N/A if (!ped_device_write (disk->dev, ptes,
1N/A disk->dev->length - 1 -
1N/A ptes_size / disk->dev->sector_size,
1N/A ptes_size / disk->dev->sector_size))
1N/A goto error_free_ptes;
1N/A
1N/A free (ptes);
1N/A return ped_device_sync (disk->dev);
1N/A
1N/Aerror_free_ptes:
1N/A free (ptes);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A#endif /* !DISCOVER_ONLY */
1N/A
1N/Astatic int
1N/Aadd_metadata_part (PedDisk *disk, PedSector start, PedSector length)
1N/A{
1N/A PedPartition *part;
1N/A PedConstraint *constraint_exact;
1N/A PED_ASSERT (disk != NULL, return 0);
1N/A
1N/A part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
1N/A start, start + length - 1);
1N/A if (!part)
1N/A goto error;
1N/A
1N/A constraint_exact = ped_constraint_exact (&part->geom);
1N/A if (!ped_disk_add_partition (disk, part, constraint_exact))
1N/A goto error_destroy_constraint;
1N/A ped_constraint_destroy (constraint_exact);
1N/A return 1;
1N/A
1N/Aerror_destroy_constraint:
1N/A ped_constraint_destroy (constraint_exact);
1N/A ped_partition_destroy (part);
1N/Aerror:
1N/A return 0;
1N/A}
1N/A
1N/Astatic PedPartition *
1N/Agpt_partition_new (const PedDisk *disk,
1N/A PedPartitionType part_type,
1N/A const PedFileSystemType *fs_type, PedSector start,
1N/A PedSector end)
1N/A{
1N/A PedPartition *part;
1N/A GPTPartitionData *gpt_part_data;
1N/A
1N/A part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
1N/A if (!part)
1N/A goto error;
1N/A
1N/A if (part_type != 0)
1N/A return part;
1N/A
1N/A gpt_part_data = part->disk_specific =
1N/A ped_malloc (sizeof (GPTPartitionData));
1N/A if (!gpt_part_data)
1N/A goto error_free_part;
1N/A
1N/A gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1N/A gpt_part_data->lvm = 0;
1N/A gpt_part_data->raid = 0;
1N/A gpt_part_data->boot = 0;
1N/A gpt_part_data->bios_grub = 0;
1N/A gpt_part_data->hp_service = 0;
1N/A gpt_part_data->hidden = 0;
1N/A gpt_part_data->msftres = 0;
1N/A gpt_part_data->msftrecv = 0;
1N/A gpt_part_data->atvrecv = 0;
1N/A uuid_generate ((unsigned char *) &gpt_part_data->uuid);
1N/A swap_uuid_and_efi_guid ((unsigned char *) (&gpt_part_data->uuid));
1N/A memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
1N/A return part;
1N/A
1N/Aerror_free_part:
1N/A _ped_partition_free (part);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic PedPartition *
1N/Agpt_partition_duplicate (const PedPartition *part)
1N/A{
1N/A PedPartition *result;
1N/A GPTPartitionData *part_data = part->disk_specific;
1N/A GPTPartitionData *result_data;
1N/A
1N/A result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
1N/A part->geom.start, part->geom.end);
1N/A if (!result)
1N/A goto error;
1N/A result->num = part->num;
1N/A
1N/A if (result->type != 0)
1N/A return result;
1N/A
1N/A result_data = result->disk_specific =
1N/A ped_malloc (sizeof (GPTPartitionData));
1N/A if (!result_data)
1N/A goto error_free_part;
1N/A
1N/A result_data->type = part_data->type;
1N/A result_data->uuid = part_data->uuid;
1N/A strcpy (result_data->name, part_data->name);
1N/A return result;
1N/A
1N/Aerror_free_part:
1N/A _ped_partition_free (result);
1N/Aerror:
1N/A return NULL;
1N/A}
1N/A
1N/Astatic void
1N/Agpt_partition_destroy (PedPartition *part)
1N/A{
1N/A if (part->type == 0)
1N/A {
1N/A PED_ASSERT (part->disk_specific != NULL, return);
1N/A free (part->disk_specific);
1N/A }
1N/A
1N/A _ped_partition_free (part);
1N/A}
1N/A
1N/Astatic int
1N/Agpt_partition_set_system (PedPartition *part,
1N/A const PedFileSystemType *fs_type)
1N/A{
1N/A GPTPartitionData *gpt_part_data = part->disk_specific;
1N/A
1N/A PED_ASSERT (gpt_part_data != NULL, return 0);
1N/A
1N/A part->fs_type = fs_type;
1N/A
1N/A if (gpt_part_data->lvm)
1N/A {
1N/A gpt_part_data->type = PARTITION_LVM_GUID;
1N/A return 1;
1N/A }
1N/A if (gpt_part_data->raid)
1N/A {
1N/A gpt_part_data->type = PARTITION_RAID_GUID;
1N/A return 1;
1N/A }
1N/A if (gpt_part_data->boot)
1N/A {
1N/A gpt_part_data->type = PARTITION_SYSTEM_GUID;
1N/A return 1;
1N/A }
1N/A if (gpt_part_data->bios_grub)
1N/A {
1N/A gpt_part_data->type = PARTITION_BIOS_GRUB_GUID;
1N/A return 1;
1N/A }
1N/A if (gpt_part_data->hp_service)
1N/A {
1N/A gpt_part_data->type = PARTITION_HPSERVICE_GUID;
1N/A return 1;
1N/A }
1N/A if (gpt_part_data->msftres)
1N/A {
1N/A gpt_part_data->type = PARTITION_MSFT_RESERVED_GUID;
1N/A return 1;
1N/A }
1N/A if (gpt_part_data->msftrecv)
1N/A {
1N/A gpt_part_data->type = PARTITION_MSFT_RECOVERY;
1N/A return 1;
1N/A }
1N/A if (gpt_part_data->atvrecv)
1N/A {
1N/A gpt_part_data->type = PARTITION_APPLE_TV_RECOVERY_GUID;
1N/A return 1;
1N/A }
1N/A
1N/A if (fs_type)
1N/A {
1N/A if (strncmp (fs_type->name, "fat", 3) == 0
1N/A || strcmp (fs_type->name, "ntfs") == 0)
1N/A {
1N/A gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1N/A return 1;
1N/A }
1N/A if (strncmp (fs_type->name, "hfs", 3) == 0)
1N/A {
1N/A gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
1N/A return 1;
1N/A }
1N/A if (strstr (fs_type->name, "swap"))
1N/A {
1N/A gpt_part_data->type = PARTITION_SWAP_GUID;
1N/A return 1;
1N/A }
1N/A }
1N/A
1N/A gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
1N/A return 1;
1N/A}
1N/A
1N/A/* Allocate metadata partitions for the GPTH and PTES */
1N/Astatic int
1N/Agpt_alloc_metadata (PedDisk *disk)
1N/A{
1N/A PedSector gptlength, pteslength = 0;
1N/A GPTDiskData *gpt_disk_data;
1N/A
1N/A PED_ASSERT (disk != NULL, return 0);
1N/A PED_ASSERT (disk->dev != NULL, return 0);
1N/A PED_ASSERT (disk->disk_specific != NULL, return 0);
1N/A gpt_disk_data = disk->disk_specific;
2N/A int writing_entry_count = MAX(gpt_disk_data->entry_count,
2N/A GPT_DEFAULT_PARTITION_ENTRIES);
1N/A
1N/A gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
1N/A disk->dev->sector_size);
2N/A pteslength = ped_div_round_up (writing_entry_count
1N/A * sizeof (GuidPartitionEntry_t),
1N/A disk->dev->sector_size);
1N/A
1N/A /* metadata at the start of the disk includes the MBR */
1N/A if (!add_metadata_part (disk, GPT_PMBR_LBA,
1N/A GPT_PMBR_SECTORS + gptlength + pteslength))
1N/A return 0;
1N/A
1N/A /* metadata at the end of the disk */
1N/A if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
1N/A gptlength + pteslength))
1N/A return 0;
1N/A
1N/A return 1;
1N/A}
1N/A
1N/A/* Does nothing, as the read/new/destroy functions maintain part->num */
1N/Astatic int
1N/Agpt_partition_enumerate (PedPartition *part)
1N/A{
1N/A GPTDiskData *gpt_disk_data = part->disk->disk_specific;
1N/A int i;
1N/A
1N/A /* never change the partition numbers */
1N/A if (part->num != -1)
1N/A return 1;
1N/A
1N/A for (i = 1; i <= gpt_disk_data->entry_count; i++)
1N/A {
1N/A if (!ped_disk_get_partition (part->disk, i))
1N/A {
1N/A part->num = i;
1N/A return 1;
1N/A }
1N/A }
1N/A
1N/A PED_ASSERT (0, return 0);
1N/A
1N/A return 0; /* used if debug is disabled */
1N/A}
1N/A
1N/Astatic int
1N/Agpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
1N/A{
1N/A GPTPartitionData *gpt_part_data;
1N/A PED_ASSERT (part != NULL, return 0);
1N/A PED_ASSERT (part->disk_specific != NULL, return 0);
1N/A gpt_part_data = part->disk_specific;
1N/A
1N/A switch (flag)
1N/A {
1N/A case PED_PARTITION_BOOT:
1N/A gpt_part_data->boot = state;
1N/A if (state)
1N/A gpt_part_data->raid
1N/A = gpt_part_data->lvm
1N/A = gpt_part_data->bios_grub
1N/A = gpt_part_data->hp_service
1N/A = gpt_part_data->msftres
1N/A = gpt_part_data->msftrecv
1N/A = gpt_part_data->atvrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_BIOS_GRUB:
1N/A gpt_part_data->bios_grub = state;
1N/A if (state)
1N/A gpt_part_data->raid
1N/A = gpt_part_data->lvm
1N/A = gpt_part_data->boot
1N/A = gpt_part_data->hp_service
1N/A = gpt_part_data->msftres
1N/A = gpt_part_data->msftrecv
1N/A = gpt_part_data->atvrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_RAID:
1N/A gpt_part_data->raid = state;
1N/A if (state)
1N/A gpt_part_data->boot
1N/A = gpt_part_data->lvm
1N/A = gpt_part_data->bios_grub
1N/A = gpt_part_data->hp_service
1N/A = gpt_part_data->msftres
1N/A = gpt_part_data->msftrecv
1N/A = gpt_part_data->atvrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_LVM:
1N/A gpt_part_data->lvm = state;
1N/A if (state)
1N/A gpt_part_data->boot
1N/A = gpt_part_data->raid
1N/A = gpt_part_data->bios_grub
1N/A = gpt_part_data->hp_service
1N/A = gpt_part_data->msftres
1N/A = gpt_part_data->msftrecv
1N/A = gpt_part_data->atvrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_HPSERVICE:
1N/A gpt_part_data->hp_service = state;
1N/A if (state)
1N/A gpt_part_data->boot
1N/A = gpt_part_data->raid
1N/A = gpt_part_data->lvm
1N/A = gpt_part_data->bios_grub
1N/A = gpt_part_data->msftres
1N/A = gpt_part_data->msftrecv
1N/A = gpt_part_data->atvrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_MSFT_RESERVED:
1N/A gpt_part_data->msftres = state;
1N/A if (state)
1N/A gpt_part_data->boot
1N/A = gpt_part_data->raid
1N/A = gpt_part_data->lvm
1N/A = gpt_part_data->bios_grub
1N/A = gpt_part_data->hp_service
1N/A = gpt_part_data->msftrecv
1N/A = gpt_part_data->atvrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_DIAG:
1N/A gpt_part_data->msftrecv = state;
1N/A if (state)
1N/A gpt_part_data->boot
1N/A = gpt_part_data->raid
1N/A = gpt_part_data->lvm
1N/A = gpt_part_data->bios_grub
1N/A = gpt_part_data->hp_service
1N/A = gpt_part_data->msftres
1N/A = gpt_part_data->atvrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_APPLE_TV_RECOVERY:
1N/A gpt_part_data->atvrecv = state;
1N/A if (state)
1N/A gpt_part_data->boot
1N/A = gpt_part_data->raid
1N/A = gpt_part_data->lvm
1N/A = gpt_part_data->bios_grub
1N/A = gpt_part_data->hp_service
1N/A = gpt_part_data->msftres
1N/A = gpt_part_data->msftrecv = 0;
1N/A return gpt_partition_set_system (part, part->fs_type);
1N/A case PED_PARTITION_HIDDEN:
1N/A gpt_part_data->hidden = state;
1N/A return 1;
1N/A case PED_PARTITION_SWAP:
1N/A case PED_PARTITION_ROOT:
1N/A case PED_PARTITION_LBA:
1N/A default:
1N/A return 0;
1N/A }
1N/A return 1;
1N/A}
1N/A
1N/Astatic int
1N/Agpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
1N/A{
1N/A GPTPartitionData *gpt_part_data;
1N/A PED_ASSERT (part->disk_specific != NULL, return 0);
1N/A gpt_part_data = part->disk_specific;
1N/A
1N/A switch (flag)
1N/A {
1N/A case PED_PARTITION_RAID:
1N/A return gpt_part_data->raid;
1N/A case PED_PARTITION_LVM:
1N/A return gpt_part_data->lvm;
1N/A case PED_PARTITION_BOOT:
1N/A return gpt_part_data->boot;
1N/A case PED_PARTITION_BIOS_GRUB:
1N/A return gpt_part_data->bios_grub;
1N/A case PED_PARTITION_HPSERVICE:
1N/A return gpt_part_data->hp_service;
1N/A case PED_PARTITION_MSFT_RESERVED:
1N/A return gpt_part_data->msftres;
1N/A case PED_PARTITION_DIAG:
1N/A return gpt_part_data->msftrecv;
1N/A case PED_PARTITION_APPLE_TV_RECOVERY:
1N/A return gpt_part_data->atvrecv;
1N/A case PED_PARTITION_HIDDEN:
1N/A return gpt_part_data->hidden;
1N/A case PED_PARTITION_SWAP:
1N/A case PED_PARTITION_LBA:
1N/A case PED_PARTITION_ROOT:
1N/A default:
1N/A return 0;
1N/A }
1N/A return 0;
1N/A}
1N/A
1N/Astatic int
1N/Agpt_partition_is_flag_available (const PedPartition *part,
1N/A PedPartitionFlag flag)
1N/A{
1N/A switch (flag)
1N/A {
1N/A case PED_PARTITION_RAID:
1N/A case PED_PARTITION_LVM:
1N/A case PED_PARTITION_BOOT:
1N/A case PED_PARTITION_BIOS_GRUB:
1N/A case PED_PARTITION_HPSERVICE:
1N/A case PED_PARTITION_MSFT_RESERVED:
1N/A case PED_PARTITION_DIAG:
1N/A case PED_PARTITION_APPLE_TV_RECOVERY:
1N/A case PED_PARTITION_HIDDEN:
1N/A return 1;
1N/A case PED_PARTITION_SWAP:
1N/A case PED_PARTITION_ROOT:
1N/A case PED_PARTITION_LBA:
1N/A default:
1N/A return 0;
1N/A }
1N/A return 0;
1N/A}
1N/A
1N/Astatic void
1N/Agpt_partition_set_name (PedPartition *part, const char *name)
1N/A{
1N/A GPTPartitionData *gpt_part_data = part->disk_specific;
1N/A
1N/A strncpy (gpt_part_data->name, name, 36);
1N/A gpt_part_data->name[36] = 0;
1N/A}
1N/A
1N/Astatic const char *
1N/Agpt_partition_get_name (const PedPartition *part)
1N/A{
1N/A GPTPartitionData *gpt_part_data = part->disk_specific;
1N/A return gpt_part_data->name;
1N/A}
1N/A
1N/Astatic int
1N/Agpt_get_max_primary_partition_count (const PedDisk *disk)
1N/A{
1N/A const GPTDiskData *gpt_disk_data = disk->disk_specific;
1N/A return gpt_disk_data->entry_count;
1N/A}
1N/A
1N/A/*
1N/A * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
1N/A * According to the specs the first LBA (LBA0) is not relevant (it exists
1N/A * to maintain compatibility). on the second LBA(LBA1) gpt places the
1N/A * header. The header is as big as the block size. After the header we
1N/A * find the Entry array. Each element of said array, describes each
1N/A * partition. One can have as much elements as can fit between the end of
1N/A * the second LBA (where the header ends) and the FirstUsableLBA.
1N/A * FirstUsableLBA is the first logical block that is used for contents
1N/A * and is defined in header.
1N/A *
1N/A * /---------------------------------------------------\
1N/A * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
1N/A * | | BLOCK1 | | |
1N/A * \---------------------------------------------------/
1N/A * / \
1N/A * /----------/ \----------\
1N/A * /-----------------------------------------\
1N/A * | E1 | E2 | E3 |...............| EN |
1N/A * \-----------------------------------------/
1N/A *
1N/A * The number of possible partitions or supported partitions is:
1N/A * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
1N/A * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
1N/A */
1N/Astatic bool
1N/Agpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
1N/A{
1N/A GuidPartitionTableHeader_t *pth = NULL;
1N/A uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
1N/A
1N/A if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
1N/A || ped_device_read (disk->dev, pth_raw,
1N/A disk->dev->length, GPT_HEADER_SECTORS))
1N/A pth = pth_new_from_raw (disk->dev, pth_raw);
1N/A free (pth_raw);
1N/A
1N/A if (pth == NULL)
1N/A return false;
1N/A
1N/A *max_n = (disk->dev->sector_size * (pth->FirstUsableLBA - 2)
1N/A / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
1N/A pth_free (pth);
1N/A return true;
1N/A}
1N/A
1N/Astatic PedConstraint *
1N/A_non_metadata_constraint (const PedDisk *disk)
1N/A{
1N/A GPTDiskData *gpt_disk_data = disk->disk_specific;
1N/A
1N/A return ped_constraint_new_from_max (&gpt_disk_data->data_area);
1N/A}
1N/A
1N/Astatic int
1N/Agpt_partition_align (PedPartition *part, const PedConstraint *constraint)
1N/A{
1N/A PED_ASSERT (part != NULL, return 0);
1N/A
1N/A if (_ped_partition_attempt_align (part, constraint,
1N/A _non_metadata_constraint (part->disk)))
1N/A return 1;
1N/A
1N/A#ifndef DISCOVER_ONLY
1N/A ped_exception_throw (PED_EXCEPTION_ERROR,
1N/A PED_EXCEPTION_CANCEL,
1N/A _("Unable to satisfy all constraints on the partition."));
1N/A#endif
1N/A return 0;
1N/A}
1N/A
1N/A#include "pt-common.h"
1N/APT_define_limit_functions (gpt)
1N/A
1N/Astatic PedDiskOps gpt_disk_ops =
1N/A{
1N/A .clobber = NULL,
1N/A .write = NULL_IF_DISCOVER_ONLY (gpt_write),
1N/A
1N/A .partition_set_name = gpt_partition_set_name,
1N/A .partition_get_name = gpt_partition_get_name,
1N/A
1N/A PT_op_function_initializers (gpt)
1N/A};
1N/A
1N/Astatic PedDiskType gpt_disk_type =
1N/A{
1N/A .next = NULL,
1N/A .name = "gpt",
1N/A .ops = &gpt_disk_ops,
1N/A .features = PED_DISK_TYPE_PARTITION_NAME
1N/A};
1N/A
1N/Avoid
1N/Aped_disk_gpt_init ()
1N/A{
1N/A PED_ASSERT (sizeof (GuidPartitionEntryAttributes_t) == 8, return);
1N/A PED_ASSERT (sizeof (GuidPartitionEntry_t) == 128, return);
1N/A
1N/A ped_disk_type_register (&gpt_disk_type);
1N/A}
1N/A
1N/Avoid
1N/Aped_disk_gpt_done ()
1N/A{
1N/A ped_disk_type_unregister (&gpt_disk_type);
1N/A}