diff --git a/bsd.cc b/bsd.cc new file mode 100644 index 0000000000000000000000000000000000000000..b46ea7a3af66cfdd780fb714528aa4107e4dbd9a --- /dev/null +++ b/bsd.cc @@ -0,0 +1,307 @@ +/* bsd.cc -- Functions for loading, saving, and manipulating legacy BSD disklabel + data. */ + +/* By Rod Smith, August, 2009 */ + +/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed + under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ + +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdint.h> +#include <fcntl.h> +#include <string.h> +//#include <time.h> +#include <sys/stat.h> +#include <errno.h> +#include "crc32.h" +#include "support.h" +#include "bsd.h" + +using namespace std; + + +BSDData::BSDData(void) { + state = unknown; + signature = UINT32_C(0); + signature2 = UINT32_C(0); + sectorSize = 512; + numParts = 0; + labelFirstLBA = 0; + labelLastLBA = 0; + labelStart = LABEL_OFFSET1; // assume raw disk format +// deviceFilename[0] = '\0'; + partitions = NULL; +} // default constructor + +BSDData::~BSDData(void) { + free(partitions); +} // destructor + +int BSDData::ReadBSDData(char* device, uint64_t startSector, uint64_t endSector) { + int fd, allOK = 1; + + if ((fd = open(device, O_RDONLY)) != -1) { + ReadBSDData(fd, startSector, endSector); + } else { + allOK = 0; + } // if + + close(fd); + +// if (allOK) +// strcpy(deviceFilename, device); + + return allOK; +} // BSDData::ReadBSDData() (device filename version) + +// Load the BSD disklabel data from an already-opened disk +// file, starting with the specified sector number. +void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) { + uint8_t buffer[2048]; // I/O buffer + uint64_t startByte; + int i, err, foundSig = 0, bigEnd = 0; + int relative = 0; // assume absolute partition sector numbering + uint32_t realSig; + uint32_t* temp32; + uint16_t* temp16; + BSDRecord* tempRecords; + + labelFirstLBA = startSector; + labelLastLBA = endSector; + + // Read two sectors into memory; we'll extract data from + // this buffer. (Done to work around FreeBSD limitation) + lseek64(fd, startSector * 512, SEEK_SET); + err = read(fd, buffer, 2048); + + // Do some strangeness to support big-endian architectures... + bigEnd = (IsLittleEndian() == 0); + realSig = BSD_SIGNATURE; + if (bigEnd) + ReverseBytes(&realSig, 4); + + // Look for the signature at one of two locations + labelStart = LABEL_OFFSET1; + temp32 = (uint32_t*) &buffer[labelStart]; + signature = *temp32; + if (signature == realSig) { + temp32 = (uint32_t*) &buffer[labelStart + 132]; + signature2 = *temp32; + if (signature2 == realSig) + foundSig = 1; + } // if/else + if (!foundSig) { // look in second location + labelStart = LABEL_OFFSET2; + temp32 = (uint32_t*) &buffer[labelStart]; + signature = *temp32; + if (signature == realSig) { + temp32 = (uint32_t*) &buffer[labelStart + 132]; + signature2 = *temp32; + if (signature2 == realSig) + foundSig = 1; + } // if/else + } // if + + // Load partition metadata from the buffer.... + temp32 = (uint32_t*) &buffer[labelStart + 40]; + sectorSize = *temp32; + temp16 = (uint16_t*) &buffer[labelStart + 138]; + numParts = *temp16; + + // Make it big-endian-aware.... + if (IsLittleEndian() == 0) + ReverseMetaBytes(); + + // Check validity of the data and flag it appropriately.... + if (foundSig && (numParts <= MAX_BSD_PARTS)) { + state = bsd; + } else { + state = bsd_invalid; + } // if/else + + // If the state is good, go ahead and load the main partition data.... + if (state == bsd) { + partitions = (struct BSDRecord*) malloc(numParts * sizeof (struct BSDRecord)); + for (i = 0; i < numParts; i++) { + // Once again, we use the buffer, but index it using a BSDRecord + // pointer (dangerous, but effective).... + tempRecords = (BSDRecord*) &buffer[labelStart + 148]; + partitions[i].lengthLBA = tempRecords[i].lengthLBA; + partitions[i].firstLBA = tempRecords[i].firstLBA; + partitions[i].fsType = tempRecords[i].fsType; + if (bigEnd) { // reverse data (fsType is a single byte) + ReverseBytes(&partitions[i].lengthLBA, 4); + ReverseBytes(&partitions[i].firstLBA, 4); + } // if big-endian + // Check for signs of relative sector numbering: A "0" first sector + // number on a partition with a non-zero length -- but ONLY if the + // length is less than the disk size, since NetBSD has a habit of + // creating a disk-sized partition within a carrier MBR partition + // that's too small to house it, and this throws off everything.... + if ((partitions[i].firstLBA == 0) && (partitions[i].lengthLBA > 0) + && (partitions[i].lengthLBA < labelLastLBA)) + relative = 1; + } // for + // Some disklabels use sector numbers relative to the enclosing partition's + // start, others use absolute sector numbers. If relative numbering was + // detected above, apply a correction to all partition start sectors.... + if (relative) { + for (i = 0; i < numParts; i++) { + partitions[i].firstLBA += startSector; + } // for + } // if + } // if signatures OK +// DisplayBSDData(); +} // BSDData::ReadBSDData(int fd, uint64_t startSector) + +// Reverse metadata's byte order; called only on big-endian systems +void BSDData::ReverseMetaBytes(void) { + ReverseBytes(&signature, 4); + ReverseBytes(§orSize, 4); + ReverseBytes(&signature2, 4); + ReverseBytes(&numParts, 2); +} // BSDData::ReverseMetaByteOrder() + +// Display basic BSD partition data. Used for debugging. +void BSDData::DisplayBSDData(void) { + int i; + + if (state == bsd) { + printf("BSD partitions:\n"); + printf("Number\t Start (sector)\t Length (sectors)\tType\n"); + for (i = 0; i < numParts; i++) { + printf("%4d\t%13lu\t%15lu \t0x%02X\n", i + 1, + (unsigned long) partitions[i].firstLBA, + (unsigned long) partitions[i].lengthLBA, partitions[i].fsType); + } // for + } // if +} // BSDData::DisplayBSDData() + +// Displays the BSD disklabel state. Called during program launch to inform +// the user about the partition table(s) status +int BSDData::ShowState(void) { + int retval = 0; + + switch (state) { + case bsd_invalid: + printf(" BSD: not present\n"); + break; + case bsd: + printf(" BSD: present\n"); + retval = 1; + break; + default: + printf("\a BSD: unknown -- bug!\n"); + break; + } // switch + return retval; +} // BSDData::ShowState() + +// Returns the BSD table's partition type code +uint8_t BSDData::GetType(int i) { + uint8_t retval = 0; // 0 = "unused" + + if ((i < numParts) && (i >= 0) && (state == bsd) && (partitions != 0)) + retval = partitions[i].fsType; + + return(retval); +} // BSDData::GetType() + +// Returns the number of the first sector of the specified partition +uint64_t BSDData::GetFirstSector(int i) { + uint64_t retval = UINT64_C(0); + + if ((i < numParts) && (i >= 0) && (state == bsd) && (partitions != 0)) + retval = (uint64_t) partitions[i].firstLBA; + + return retval; +} // BSDData::GetFirstSector + +// Returns the length (in sectors) of the specified partition +uint64_t BSDData::GetLength(int i) { + uint64_t retval = UINT64_C(0); + + if ((i < numParts) && (i >= 0) && (state == bsd) && (partitions != 0)) + retval = (uint64_t) partitions[i].lengthLBA; + + return retval; +} // BSDData::GetLength() + +// Returns the number of partitions defined in the current table +int BSDData::GetNumParts(void) { + return numParts; +} // BSDData::GetNumParts() + +// Returns the specified partition as a GPT partition. Used in BSD-to-GPT +// conversion process +GPTPart BSDData::AsGPT(int i) { + GPTPart guid; // dump data in here, then return it + uint64_t sectorOne, sectorEnd; // first & last sectors of partition + char tempStr[NAME_SIZE]; // temporary string for holding GPT name + int passItOn = 1; // Set to 0 if partition is empty or invalid + + guid.BlankPartition(); + sectorOne = (uint64_t) partitions[i].firstLBA; + sectorEnd = sectorOne + (uint64_t) partitions[i].lengthLBA; + if (sectorEnd > 0) sectorEnd--; + // Note on above: BSD partitions sometimes have a length of 0 and a start + // sector of 0. With unsigned ints, the usual (start + length - 1) to + // find the end will result in a huge number, which will be confusing + + // Do a few sanity checks on the partition before we pass it on.... + // First, check that it falls within the bounds of its container + // and that it starts before it ends.... + if ((sectorOne < labelFirstLBA) || (sectorEnd > labelLastLBA) || (sectorOne > sectorEnd)) + passItOn = 0; + // Some disklabels include a pseudo-partition that's the size of the entire + // disk or containing partition. Don't return it. + if ((sectorOne <= labelFirstLBA) && (sectorEnd >= labelLastLBA) && + (GetType(i) == 0)) + passItOn = 0; + // If the end point is 0, it's not a valid partition. + if (sectorEnd == 0) + passItOn = 0; + + if (passItOn) { + guid.SetFirstLBA(sectorOne); + guid.SetLastLBA(sectorEnd); + // Now set a random unique GUID for the partition.... + guid.SetUniqueGUID(1); + // ... zero out the attributes and name fields.... + guid.SetAttributes(UINT64_C(0)); + // Most BSD disklabel type codes seem to be archaic or rare. + // They're also ambiguous; a FreeBSD filesystem is impossible + // to distinguish from a NetBSD one. Thus, these code assignment + // are going to be rough to begin with. For a list of meanings, + // see http://fxr.watson.org/fxr/source/sys/dtype.h?v=DFBSD, + // or Google it. + switch (GetType(i)) { + case 1: // BSD swap + guid.SetType(0xa502); break; + case 7: // BSD FFS + guid.SetType(0xa503); break; + case 8: case 11: // MS-DOS or HPFS + guid.SetType(0x0700); break; + case 9: // log-structured fs + guid.SetType(0xa903); break; + case 13: // bootstrap + guid.SetType(0xa501); break; + case 14: // vinum + guid.SetType(0xa505); break; + case 15: // RAID + guid.SetType(0xa903); break; + case 27: // FreeBSD ZFS + guid.SetType(0xa504); break; + default: + guid.SetType(0x0700); break; + } // switch + // Set the partition name to the name of the type code.... + guid.SetName((unsigned char*) guid.GetNameType(tempStr)); + } // if + return guid; +} // BSDData::AsGPT() diff --git a/bsd.h b/bsd.h new file mode 100644 index 0000000000000000000000000000000000000000..b35d921b9fa61586bbf19153ae5c25404b6b18cb --- /dev/null +++ b/bsd.h @@ -0,0 +1,85 @@ +/* bsd.h -- BSD disklabel data structure definitions, types, and functions */ + +/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed + under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ + +#include <stdint.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include "gptpart.h" + +#ifndef __BSD_STRUCTS +#define __BSD_STRUCTS + +#define BSD_SIGNATURE UINT32_C(0x82564557) + +#define LABEL_OFFSET1 64 /* BSD disklabels can start at one of these two */ +#define LABEL_OFFSET2 512 /* values; check both for valid signatures */ + +// FreeBSD documents a maximum # of partitions of 8, but I saw 16 on a NetBSD +// disk. I'm quadrupling that for further safety. Note that BSDReadData() +// uses a 2048-byte I/O buffer. In combination with LABEL_OFFSET2 and the +// additional 148-byte offset to the actual partition data, that gives a +// theoretical maximum of 86.75 partitions that the program can handle. +#define MAX_BSD_PARTS 64 + + +using namespace std; + +/**************************************** + * * + * BSDData class and related structures * + * * + ****************************************/ + +// Possible states of the MBR +enum BSDValidity {unknown, bsd_invalid, bsd}; + +// Data for a single BSD partition record +struct BSDRecord { // the partition table + uint32_t lengthLBA; // number of sectors in partition + uint32_t firstLBA; // starting sector + uint32_t fragSize; // filesystem basic fragment size + uint8_t fsType; // filesystem type, see below + uint8_t frag; // filesystem fragments per block + uint16_t pcpg; /* filesystem cylinders per group */ // was u_uint16_t +}; + +// Full data in tweaked MBR format +class BSDData { + protected: + // We only need a few items from the main BSD disklabel data structure.... + uint32_t signature; // the magic number + uint32_t sectorSize; // # of bytes per sector + uint32_t signature2; // the magic number (again) + uint16_t numParts; // number of partitions in table + BSDRecord* partitions; // partition array + + // Above are basic BSD disklabel data; now add more stuff.... +// uint64_t offset; // starting point in blocks + uint64_t labelStart; // BSD disklabel start point in bytes from firstLBA + uint64_t labelFirstLBA; // first sector of BSD disklabel (partition or disk) + uint64_t labelLastLBA; // final sector of BSD disklabel +// char deviceFilename[256]; + BSDValidity state; +// struct BSDRecord* GetPartition(int i); // Return BSD partition + public: + BSDData(void); + ~BSDData(void); + int ReadBSDData(char* deviceFilename, uint64_t startSector, uint64_t endSector); + void ReadBSDData(int fd, uint64_t startSector, uint64_t endSector); + void ReverseMetaBytes(void); + void DisplayBSDData(void); +// int ConvertBSDParts(struct GPTPartition gptParts[]); + int ShowState(void); // returns 1 if BSD disklabel detected + int IsDisklabel(void) {return (state == bsd);} + + // Functions to extract data on specific partitions.... + uint8_t GetType(int i); + uint64_t GetFirstSector(int i); + uint64_t GetLength(int i); + int GetNumParts(void); + GPTPart AsGPT(int i); // Return BSD part. as GPT part. +}; // struct MBRData + +#endif diff --git a/gptpart.cc b/gptpart.cc new file mode 100644 index 0000000000000000000000000000000000000000..cb622d352cbc2c16caf976cfceb49f10df9e29c0 --- /dev/null +++ b/gptpart.cc @@ -0,0 +1,274 @@ +// +// C++ Implementation: gptpart +// +// Description: Class to implement a SINGLE GPT partition +// +// +// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009 +// +// Copyright: See COPYING file that comes with this distribution +// +// +/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed + under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ + +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#include <stdio.h> +#include <string.h> +#include "gptpart.h" +#include "attributes.h" + +using namespace std; + +PartTypes GPTPart::typeHelper; + +GPTPart::GPTPart(void) { +} // Default constructor + +GPTPart::~GPTPart(void) { +} // destructor + +// Return partition's name field +unsigned char* GPTPart::GetName(unsigned char* ref) { + if (ref == NULL) + ref = (unsigned char*) malloc(NAME_SIZE * sizeof (unsigned char)); + strcpy((char*) ref, (char*) name); + return ref; +} // GPTPart::GetName() + +// Return the gdisk-specific two-byte hex code for the partition +uint16_t GPTPart::GetHexType(void) { + return typeHelper.GUIDToID(partitionType); +} // GPTPart::GetHexType() + +// Return a plain-text description of the partition type (e.g., "Linux/Windows +// data" or "Linux swap"). +char* GPTPart::GetNameType(char* theName) { + return typeHelper.GUIDToName(partitionType, theName); +} // GPTPart::GetNameType() + +// Compute and return the partition's length (or 0 if the end is incorrectly +// set before the beginning). +uint64_t GPTPart::GetLengthLBA(void) { + uint64_t length = 0; + if (firstLBA <= lastLBA) + length = lastLBA - firstLBA + UINT64_C(1); + return length; +} // GPTPart::GetLengthLBA() + +GPTPart & GPTPart::operator=(const GPTPart & orig) { + int i; + + partitionType = orig.partitionType; + uniqueGUID = orig.uniqueGUID; + firstLBA = orig.firstLBA; + lastLBA = orig.lastLBA; + attributes = orig.attributes; + for (i = 0; i < NAME_SIZE; i++) + name[i] = orig.name[i]; +} // assignment operator + +// Sets the unique GUID to a value of 0 or a random value, +// depending on the parameter: 0 = 0, anything else = random +void GPTPart::SetUniqueGUID(int zeroOrRandom) { + if (zeroOrRandom == 0) { + uniqueGUID.data1 = 0; + uniqueGUID.data2 = 0; + } else { + // rand() is only 32 bits on 32-bit systems, so multiply together to + // fill a 64-bit value. + uniqueGUID.data1 = (uint64_t) rand() * (uint64_t) rand(); + uniqueGUID.data2 = (uint64_t) rand() * (uint64_t) rand(); + } +} // GPTPart::SetUniqueGUID() + +// Blank (delete) a single partition +void GPTPart::BlankPartition(void) { + int j; + GUIDData zeroGUID; + + zeroGUID.data1 = 0; + zeroGUID.data2 = 0; + uniqueGUID = zeroGUID; + partitionType = zeroGUID; + firstLBA = 0; + lastLBA = 0; + attributes = 0; + for (j = 0; j < NAME_SIZE; j++) + name[j] = '\0'; +} // GPTPart::BlankPartition + +// Returns 1 if the two partitions overlap, 0 if they don't +int GPTPart::DoTheyOverlap(GPTPart* other) { + int theyDo = 0; + + // Don't bother checking unless these are defined (both start and end points + // are 0 for undefined partitions, so just check the start points) + if ((firstLBA != 0) && (other->firstLBA != 0)) { + if ((firstLBA < other->lastLBA) && (lastLBA >= other->firstLBA)) + theyDo = 1; + if ((other->firstLBA < lastLBA) && (other->lastLBA >= firstLBA)) + theyDo = 1; + } // if + return (theyDo); +} // GPTPart::DoTheyOverlap() + +// Reverse the bytes of integral data types; used on big-endian systems. +void GPTPart::ReversePartBytes(void) { + ReverseBytes(&partitionType.data1, 8); + ReverseBytes(&partitionType.data2, 8); + ReverseBytes(&uniqueGUID.data1, 8); + ReverseBytes(&uniqueGUID.data2, 8); + ReverseBytes(&firstLBA, 8); + ReverseBytes(&lastLBA, 8); + ReverseBytes(&attributes, 8); +} // GPTPart::ReverseBytes() + +// Display summary information; does nothing if the partition is empty. +void GPTPart::ShowSummary(int i, uint32_t blockSize, char* sizeInSI) { + int j; + + if (firstLBA != 0) { + BytesToSI(blockSize * (lastLBA - firstLBA + 1), sizeInSI); + printf("%4d %14lu %14lu", i + 1, (unsigned long) firstLBA, + (unsigned long) lastLBA); + printf(" %-10s %04X ", sizeInSI, + typeHelper.GUIDToID(partitionType)); + j = 0; + while ((name[j] != '\0') && (j < 44)) { + printf("%c", name[j]); + j += 2; + } // while + printf("\n"); + } // if +} // GPTPart::ShowSummary() + +// Show detailed partition information. Does nothing if the partition is +// empty (as determined by firstLBA being 0). +void GPTPart::ShowDetails(uint32_t blockSize) { + char temp[255]; + int i; + uint64_t size; + + if (firstLBA != 0) { + printf("Partition GUID code: %s ", GUIDToStr(partitionType, temp)); + printf("(%s)\n", typeHelper.GUIDToName(partitionType, temp)); + printf("Partition unique GUID: %s\n", GUIDToStr(uniqueGUID, temp)); + + printf("First sector: %llu (at %s)\n", (unsigned long long) firstLBA, + BytesToSI(firstLBA * blockSize, temp)); + printf("Last sector: %llu (at %s)\n", (unsigned long long) lastLBA, + BytesToSI(lastLBA * blockSize, temp)); + size = (lastLBA - firstLBA + 1); + printf("Partition size: %llu sectors (%s)\n", (unsigned long long) + size, BytesToSI(size * ((uint64_t) blockSize), temp)); + printf("Attribute flags: %016llx\n", (unsigned long long) attributes); + printf("Partition name: "); + i = 0; + while ((name[i] != '\0') && (i < NAME_SIZE)) { + printf("%c", name[i]); + i += 2; + } // while + printf("\n"); + } // if +} // GPTPart::ShowDetails() + +/**************************************** + * Functions requiring user interaction * + ****************************************/ + +// Change the type code on the partition. +void GPTPart::ChangeType(void) { + char typeName[255], line[255]; + int typeNum = 0xFFFF; +// uint16_t typeNum = 0xFFFF; + GUIDData newType; + + printf("Current type is '%s'\n", GetNameType(line)); +// printf("Current type is '%s'\n", typeHelper.GUIDToName(partitionType, typeName)); + while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) { + printf("Hex code (L to show codes, 0 to enter raw code): "); + fgets(line, 255, stdin); + sscanf(line, "%X", &typeNum); + if ((line[0] == 'L') || (line[0] == 'l')) + typeHelper.ShowTypes(); + } // while + if (typeNum != 0) // user entered a code, so convert it + newType = typeHelper.IDToGUID((uint16_t) typeNum); + else // user wants to enter the GUID directly, so do that + newType = GetGUID(); + partitionType = newType; + printf("Changed system type of partition to '%s'\n", + typeHelper.GUIDToName(partitionType, typeName)); +} // GPTPart::ChangeType() + +// Set the name for a partition to theName, or prompt for a name if +// theName is a NULL pointer. Note that theName is a standard C-style +// string, although the GUID partition definition requires a UTF-16LE +// string. This function creates a simple-minded copy for this. +void GPTPart::SetName(unsigned char* theName) { + char newName[NAME_SIZE]; // New name + int i; + + // Blank out new name string, just to be on the safe side.... + for (i = 0; i < NAME_SIZE; i++) + newName[i] = '\0'; + + if (theName == NULL) { // No name specified, so get one from the user + printf("Enter name: "); + fgets(newName, NAME_SIZE / 2, stdin); + + // Input is likely to include a newline, so remove it.... + i = strlen(newName); + if (newName[i - 1] == '\n') + newName[i - 1] = '\0'; + } else { + strcpy(newName, (char*) theName); + } // if + + // Copy the C-style ASCII string from newName into a form that the GPT + // table will accept.... + for (i = 0; i < NAME_SIZE; i++) { + if ((i % 2) == 0) { + name[i] = newName[(i / 2)]; + } else { + name[i] = '\0'; + } // if/else + } // for +} // GPTPart::SetName() + +/*********************************** + * Non-class but related functions * + ***********************************/ + +// Recursive quick sort algorithm for GPT partitions. Note that if there +// are any empties in the specified range, they'll be sorted to the +// start, resulting in a sorted set of partitions that begins with +// partition 2, 3, or higher. +void QuickSortGPT(GPTPart* partitions, int start, int finish) { + uint64_t starterValue; // starting location of median partition + int left, right; + GPTPart temp; + + left = start; + right = finish; + starterValue = partitions[(start + finish) / 2].GetFirstLBA(); + do { + while (partitions[left].GetFirstLBA() < starterValue) + left++; + while (partitions[right].GetFirstLBA() > starterValue) + right--; + if (left <= right) { + temp = partitions[left]; + partitions[left] = partitions[right]; + partitions[right] = temp; + left++; + right--; + } // if + } while (left <= right); + if (start < right) QuickSortGPT(partitions, start, right); + if (finish > left) QuickSortGPT(partitions, left, finish); +} // QuickSortGPT() + diff --git a/gptpart.h b/gptpart.h new file mode 100644 index 0000000000000000000000000000000000000000..6b834ca7388204dd97bb0dc95f91d4217668b02d --- /dev/null +++ b/gptpart.h @@ -0,0 +1,89 @@ +// +// C++ Interface: gptpart +// +// Description: Class to implement a single GPT partition +// +// +// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009 +// +// Copyright: See COPYING file that comes with this distribution +// +// +/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed + under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ + +#ifndef __GPTPART_H +#define __GPTPART_H + +#include <stdint.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include "support.h" +#include "parttypes.h" + +using namespace std; + +/***************************************** + * * + * GUIDPart class and related structures * + * * + *****************************************/ + +class GPTPart { + protected: + // Caution: The non-static data in GUIDPart is precisely the right size + // to enable easy loading of the data directly from disk. If any + // non-static variables are added to the below, the data size will + // change and the program will stop working. This can be corrected by + // adjusting the data-load operation in GPTData::LoadMainTable() and + // GPTData::LoadSecondTableAsMain() and then removing the GUIDPart + // size check in SizesOK(). + struct GUIDData partitionType; + struct GUIDData uniqueGUID; + uint64_t firstLBA; + uint64_t lastLBA; + uint64_t attributes; + unsigned char name[NAME_SIZE]; + + static PartTypes typeHelper; + public: + GPTPart(void); + ~GPTPart(void); + + // Simple data retrieval: + struct GUIDData GetType(void) {return partitionType;} + uint16_t GetHexType(void); + char* GetNameType(char* theName); + struct GUIDData GetUniqueGUID(void) {return uniqueGUID;} + uint64_t GetFirstLBA(void) {return firstLBA;} + uint64_t GetLastLBA(void) {return lastLBA;} + uint64_t GetLengthLBA(void); + uint64_t GetAttributes(void) {return attributes;} + unsigned char* GetName(unsigned char* theName); + + // Simple data assignment: + void SetType(struct GUIDData t) {partitionType = t;} + void SetType(uint16_t hex) {partitionType = typeHelper.IDToGUID(hex);} + void SetUniqueGUID(struct GUIDData u) {uniqueGUID = u;} + void SetUniqueGUID(int zeroOrRandom); + void SetFirstLBA(uint64_t f) {firstLBA = f;} + void SetLastLBA(uint64_t l) {lastLBA = l;} + void SetAttributes(uint64_t a) {attributes = a;} + void SetName(unsigned char* n); + + // Additional functions + GPTPart & operator=(const GPTPart & orig); + void ShowSummary(int i, uint32_t blockSize, char* sizeInSI); // display summary information (1-line) + void ShowDetails(uint32_t blockSize); // display detailed information (multi-line) + void BlankPartition(void); // empty partition of data + int DoTheyOverlap(GPTPart* other); // returns 1 if there's overlap + void ReversePartBytes(void); // reverse byte order of all integer fields + + // Functions requiring user interaction + void ChangeType(void); // Change the type code +}; // struct GPTPart + +// A support function that doesn't quite belong in the class.... +void QuickSortGPT(GPTPart* partitions, int start, int finish); + +#endif