diff options
author | srs5694 <srs5694@users.sourceforge.net> | 2011-03-12 01:22:42 -0500 |
---|---|---|
committer | srs5694 <srs5694@users.sourceforge.net> | 2011-03-12 01:22:42 -0500 |
commit | 96312236d7f0c857efc95871a31857e24ecdc81b (patch) | |
tree | 265d546e4d67b087399a76f683f3da0e4cb88b4f | |
parent | 64cbd171067eb34054741bfcd73f0b91d727a371 (diff) | |
download | sgdisk-96312236d7f0c857efc95871a31857e24ecdc81b.tar.gz |
Added files for 0.7.0
-rw-r--r-- | gptpartnotes.cc | 190 | ||||
-rw-r--r-- | gptpartnotes.h | 49 | ||||
-rw-r--r-- | mbrpart.cc | 337 | ||||
-rw-r--r-- | mbrpart.h | 111 | ||||
-rw-r--r-- | partnotes.cc | 625 | ||||
-rw-r--r-- | partnotes.h | 100 |
6 files changed, 448 insertions, 964 deletions
diff --git a/gptpartnotes.cc b/gptpartnotes.cc deleted file mode 100644 index 2465385..0000000 --- a/gptpartnotes.cc +++ /dev/null @@ -1,190 +0,0 @@ -/* - partnotes.cc -- Class that takes notes on GPT partitions for purpose of MBR conversion - Copyright (C) 2010 Roderick W. Smith - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -*/ - -#include <iostream> -#include <stdio.h> -#include "gptpartnotes.h" -#include "gpt.h" - -using namespace std; - -GptPartNotes::GptPartNotes() { - gptParts = NULL; -} // GptPartNotes constructor - -GptPartNotes::GptPartNotes(GPTPart *parts, GPTData *gpt, int num, int s) { - gptParts = NULL; - PassPartitions(parts, gpt, num, s); -} // GptPartNotes constructor passing partition information - -/* // Destructor. Note that we do NOT delete the gptParts array, since we just -// store a pointer to an array that's allocated by the calling function. -GptPartNotes::~GptPartNotes() { -} // PartNotes destructor */ - -/************************************************************************* - * * - * Begin functions that add data to the notes, either by whole notes * - * or in smaller units. By and large these functions perform little * - * or no error checking on the added data, so they can create completely * - * bogus layouts if used carelessly. * - * * - *************************************************************************/ - -// Creates the notes linked list with as many entries as there are -// in-use GPT partitions. Note that the parts array must be pre-sorted! -// If not, this function will reject the partition table. -// Returns the number of partitions -- normally identical to num, -// unless there were problems, in which case it returns 0. -int GptPartNotes::PassPartitions(GPTPart *parts, GPTData *gpt, int num, int s) { - int i; - struct PartInfo *tempNote = NULL, *lastNote = NULL; - - if ((parts != NULL) && (num > 0)) { - blockSize = s; - gptParts = parts; - origTableSize = num; - if (notes != NULL) - DeleteNotes(); - for (i = 0; i < num; i++) { - if (gptParts[i].IsUsed()){ - tempNote = new struct PartInfo; - tempNote->next = NULL; - tempNote->firstLBA = gptParts[i].GetFirstLBA(); - tempNote->lastLBA = gptParts[i].GetLastLBA(); - if (gpt->IsFree(gptParts[i].GetFirstLBA() - 1)) { - tempNote->spaceBefore = 1; - tempNote->type = LOGICAL; - } else { - tempNote->spaceBefore = 0; - tempNote->type = PRIMARY; - } // if/else - tempNote->origPartNum = i; - tempNote->active = 0; - if (lastNote == NULL) { - lastNote = tempNote; - notes = tempNote; - } else { - lastNote->next = tempNote; - lastNote = tempNote; - } // if/else - } // if GPT partition in use - } // for - if (!IsSorted()) { - DeleteNotes(); - gptParts = NULL; - origTableSize = 0; - cerr << "The partition table must be sorted before calling GptPartNotes::PassPartitions()!\n"; - } // if - } else { - notes = NULL; - gptParts = NULL; - origTableSize = 0; - } // if/else - return origTableSize; -} // GptPartNotes::PassPartitions - -/*************************************************************************** - * * - * The following functions retrieve data, either in whole PartInfo units * - * or in smaller chunks. Some functions perform computations and * - * comparisons that may require traversing the entire linked list, perhaps * - * multiple times. * - * * - ***************************************************************************/ - -// Returns 1 if the GPT partition table is sorted, 0 if not (or if the -// pointer is NULL) -int GptPartNotes::IsSorted(void) { - int i, sorted = 1; - uint64_t lastStartLBA = 0; - - if (gptParts == NULL) { - sorted = 0; - } else { - for (i = 0; i < origTableSize; i++) { - if (lastStartLBA > gptParts[i].GetFirstLBA()) - sorted = 0; - } // for - } // if/else - return sorted; -} // GptPartNotes::IsSorted() - -/************************************************************************* - * * - * Interact with users, presenting data and/or collecting responses. May * - * change data with error detection and correction. * - * * - *************************************************************************/ - -// Display summary information for the user -void GptPartNotes::ShowSummary(void) { - size_t j; - string sizeInSI; - struct PartInfo *theNote; - - if ((gptParts != NULL) && (notes != NULL)) { - theNote = notes; - cout << "Sorted GPT partitions and their current conversion status:\n"; - cout << " Can Be\n"; - cout << "Number Boot Size Status Logical Code GPT Name\n"; - while (theNote != NULL) { - if (gptParts[theNote->origPartNum].IsUsed()) { - cout.fill(' '); - cout.width(4); - cout << theNote->origPartNum + 1 << " "; - if (theNote->active) - cout << " * "; - else - cout << " "; - sizeInSI = BytesToSI((gptParts[theNote->origPartNum].GetLastLBA() - - gptParts[theNote->origPartNum].GetFirstLBA() + 1), blockSize); - cout << " " << sizeInSI; - for (j = 0; j < 12 - sizeInSI.length(); j++) - cout << " "; - switch (theNote->type) { - case PRIMARY: - cout << "primary "; - break; - case LOGICAL: - cout << "logical "; - break; - case WILL_NOT_CONVERT: - cout << "OMITTED "; - break; - default: - cout << "**ERROR** "; - break; - } // switch - if (theNote->spaceBefore) - cout << "Y "; - else - cout << "- "; - cout.fill('0'); - cout.width(2); - cout.setf(ios::uppercase); - cout << hex << (int) theNote->hexCode << " " << dec; - cout.fill(' '); - cout << gptParts[theNote->origPartNum].GetDescription().substr(0, 25) << "\n"; - } // if - theNote = theNote->next; - } // for - } // if -} // GptPartNotes::ShowSummary() diff --git a/gptpartnotes.h b/gptpartnotes.h deleted file mode 100644 index 9466bcd..0000000 --- a/gptpartnotes.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - gptpartnotes.h -- Class that takes notes on GPT partitions for purpose of MBR conversion - Copyright (C) 2010-2011 Roderick W. Smith - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -*/ - -#ifndef __GPTPARTNOTES_H -#define __GPTPARTNOTES_H - -#include "gpt.h" -#include "gptpart.h" -#include "partnotes.h" - -using namespace std; - -class GptPartNotes : public PartNotes { - protected: - GPTPart *gptParts; - public: - GptPartNotes(); - GptPartNotes(GPTPart *parts, GPTData *gpt, int num, int blockSize); -// ~GptPartNotes(); - - // Add partition notes (little or no error checking) - int PassPartitions(GPTPart *parts, GPTData *gpt, int num, int blockSize); - - // Retrieve data or metadata - int IsSorted(void); - - // Interact with users, possibly changing data with error handling - void ShowSummary(void); - int ChangeType(int partNum, int newType); -}; - -#endif // __GPTPARTNOTES_H diff --git a/mbrpart.cc b/mbrpart.cc new file mode 100644 index 0000000..0214f48 --- /dev/null +++ b/mbrpart.cc @@ -0,0 +1,337 @@ +/* + MBRPart class, part of GPT fdisk program family. + Copyright (C) 2011 Roderick W. Smith + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#include <stddef.h> +#include <stdint.h> +#include <iostream> +#include "support.h" +#include "mbrpart.h" + +using namespace std; + +uint32_t MBRPart::numHeads = MAX_HEADS; +uint32_t MBRPart::numSecspTrack = MAX_SECSPERTRACK; +uint64_t MBRPart::diskSize = 0; +uint32_t MBRPart::blockSize = 512; +int MBRPart::numInstances = 0; + +MBRPart::MBRPart() { + int i; + + status = 0; + for (i = 0; i < 3; i++) { + firstSector[i] = 0; + lastSector[i] = 0; + } // for + partitionType = 0x00; + firstLBA = 0; + lengthLBA = 0; + includeAs = NONE; + canBePrimary = 0; + canBeLogical = 0; + if (numInstances == 0) { + numHeads = MAX_HEADS; + numSecspTrack = MAX_SECSPERTRACK; + diskSize = 0; + blockSize = 512; + } // if + numInstances++; +} + +MBRPart::MBRPart(const MBRPart& orig) { + numInstances++; + operator=(orig); +} + +MBRPart::~MBRPart() { + numInstances--; +} + +MBRPart& MBRPart::operator=(const MBRPart& orig) { + int i; + + status = orig.status; + for (i = 0; i < 3; i++) { + firstSector[i] = orig.firstSector[i]; + lastSector[i] = orig.lastSector[i]; + } // for + partitionType = orig.partitionType; + firstLBA = orig.firstLBA; + lengthLBA = orig.lengthLBA; + includeAs = orig.includeAs; + canBePrimary = orig.canBePrimary; + canBeLogical = orig.canBeLogical; + return *this; +} // MBRPart::operator=(const MBRPart& orig) + +// Set partition data from packed MBRRecord structure. +MBRPart& MBRPart::operator=(const struct MBRRecord& orig) { + int i; + + status = orig.status; + for (i = 0; i < 3; i++) { + firstSector[i] = orig.firstSector[i]; + lastSector[i] = orig.lastSector[i]; + } // for + partitionType = orig.partitionType; + firstLBA = orig.firstLBA; + lengthLBA = orig.lengthLBA; + if (lengthLBA > 0) + includeAs = PRIMARY; + else + includeAs = NONE; + return *this; +} // MBRPart::operator=(const struct MBRRecord& orig) + +/************************************************** + * * + * Set information on partitions or disks without * + * interacting with the user.... * + * * + **************************************************/ + +void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t diskSize, + uint32_t blockSize) { + numHeads = heads; + numSecspTrack = sectors; +} // MBRPart::SetGeometry + +// Empty the partition (zero out all values). +void MBRPart::Empty(void) { + status = UINT8_C(0); + firstSector[0] = UINT8_C(0); + firstSector[1] = UINT8_C(0); + firstSector[2] = UINT8_C(0); + partitionType = UINT8_C(0); + lastSector[0] = UINT8_C(0); + lastSector[1] = UINT8_C(0); + lastSector[2] = UINT8_C(0); + firstLBA = UINT32_C(0); + lengthLBA = UINT32_C(0); + includeAs = NONE; +} // MBRPart::Empty() + +// Sets the type code, but silently refuses to change it to an extended type +// code. +// Returns 1 on success, 0 on failure (extended type code) +int MBRPart::SetType(uint8_t typeCode, int isExtended) { + int allOK = 0; + + if ((isExtended == 1) || ((typeCode != 0x05) && (typeCode != 0x0f) && (typeCode != 0x85))) { + partitionType = typeCode; + allOK = 1; + } // if + return allOK; +} // MBRPart::SetType() + +void MBRPart::SetStartLBA(uint64_t start) { + if (start > UINT32_MAX) + cerr << "Partition start out of range! Continuing, but problems now likely!\n"; + firstLBA = (uint32_t) start; + RecomputeCHS(); +} // MBRPart::SetStartLBA() + +void MBRPart::SetLengthLBA(uint64_t length) { + if (length > UINT32_MAX) + cerr << "Partition length out of range! Continuing, but problems now likely!\n"; + lengthLBA = (uint32_t) length; + RecomputeCHS(); +} // MBRPart::SetLengthLBA() + +// Set the start point and length of the partition. This function takes LBA +// values, sets them directly, and sets the CHS values based on the LBA +// values and the current geometry settings. +void MBRPart::SetLocation(uint64_t start, uint64_t length) { + if ((start > UINT32_MAX) || (length > UINT32_MAX)) { + cerr << "Partition values out of range in MBRPart::SetLocation()!\n" + << "Continuing, but strange problems are now likely!\n"; + } // if + firstLBA = (uint32_t) start; + lengthLBA = (uint32_t) length; + RecomputeCHS(); + + // If this is a complete 0xEE protective MBR partition, max out its + // CHS last sector value, as per the GPT spec. (Set to 0xffffff, + // although the maximum legal MBR value is 0xfeffff, which is + // actually what GNU Parted and Apple's Disk Utility use, in + // violation of the GPT spec.) + if ((partitionType == 0xEE) && (firstLBA == 1) && (lengthLBA == diskSize - 2)) { + lastSector[0] = lastSector[1] = lastSector[2] = 0xFF; + } // if +} // MBRPart::SetLocation() + +// Store the MBR data in the packed structure used for disk I/O... +void MBRPart::StoreInStruct(MBRRecord* theStruct) { + int i; + + theStruct->firstLBA = firstLBA; + theStruct->lengthLBA = lengthLBA; + theStruct->partitionType = partitionType; + theStruct->status = status; + for (i = 0; i < 3; i++) { + theStruct->firstSector[i] = firstSector[i]; + theStruct->lastSector[i] = lastSector[i]; + } // for +} // MBRPart::StoreInStruct() + +/********************************************** +* * +* Get information on partitions or disks.... * +* * +**********************************************/ + +// Returns the last LBA value. Note that this can theoretically be a 33-bit +// value, so we return a 64-bit value. If lengthLBA == 0, returns 0, even if +// firstLBA is non-0. +uint64_t MBRPart::GetLastLBA(void) const { + if (lengthLBA > 0) + return (uint64_t) firstLBA + (uint64_t) lengthLBA - UINT64_C(1); + else + return 0; +} // MBRPart::GetLastLBA() + +// Returns 1 if other overlaps with the current partition, 0 if they don't +// overlap +int MBRPart::DoTheyOverlap (const MBRPart& other) { + return lengthLBA && other.lengthLBA && + (firstLBA <= other.GetLastLBA()) != (GetLastLBA() < other.firstLBA); +} // MBRPart::DoTheyOverlap() + +/************************************************* + * * + * Adjust information on partitions or disks.... * + * * + *************************************************/ + +void MBRPart::RecomputeCHS(void) { + if (lengthLBA > 0) { + LBAtoCHS(firstLBA, firstSector); + LBAtoCHS(firstLBA + lengthLBA - 1, lastSector); + } // if +} // MBRPart::RecomputeCHS() + +// Converts 32-bit LBA value to MBR-style CHS value. Returns 1 if conversion +// was within the range that can be expressed by CHS (including 0, for an +// empty partition), 0 if the value is outside that range, and -1 if chs is +// invalid. +int MBRPart::LBAtoCHS(uint32_t lba, uint8_t * chs) { + uint64_t cylinder, head, sector; // all numbered from 0 + uint64_t remainder; + int retval = 1; + int done = 0; + + if (chs != NULL) { + // Special case: In case of 0 LBA value, zero out CHS values.... + if (lba == 0) { + chs[0] = chs[1] = chs[2] = UINT8_C(0); + done = 1; + } // if + // If LBA value is too large for CHS, max out CHS values.... + if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) { + chs[0] = 254; + chs[1] = chs[2] = 255; + done = 1; + retval = 0; + } // if + // If neither of the above applies, compute CHS values.... + if (!done) { + cylinder = lba / (numHeads * numSecspTrack); + remainder = lba - (cylinder * numHeads * numSecspTrack); + head = remainder / numSecspTrack; + remainder -= head * numSecspTrack; + sector = remainder; + if (head < numHeads) + chs[0] = (uint8_t) head; + else + retval = 0; + if (sector < numSecspTrack) { + chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64); + chs[2] = (uint8_t) (cylinder & UINT32_C(0xFF)); + } else { + retval = 0; + } // if/else + } // if value is expressible and non-0 + } else { // Invalid (NULL) chs pointer + retval = -1; + } // if CHS pointer valid + return (retval); +} // MBRPart::LBAtoCHS() + +// Reverses the byte order, but only if we're on a big-endian platform. +// Note that most data come in 8-bit structures, so don't need reversing; +// only the LBA data needs to be reversed.... +void MBRPart::ReverseByteOrder(void) { + if (IsLittleEndian() == 0) { + ReverseBytes(&firstLBA, 4); + ReverseBytes(&lengthLBA, 4); + } // if +} // MBRPart::ReverseByteOrder() + +/************************** + * * + * User I/O functions.... * + * * + **************************/ + +// Show MBR data. Should update canBeLogical flags before calling. +// If isGpt == 1, omits the "can be logical" and "can be primary" columns. +void MBRPart::ShowData(int isGpt) { + char bootCode = ' '; + + if (status && 0x80) // it's bootable + bootCode = '*'; + cout.fill(' '); + cout << bootCode << " "; + cout.width(13); + cout << firstLBA; + cout.width(13); + cout << GetLastLBA() << " "; + switch (includeAs) { + case PRIMARY: + cout << "primary"; + break; + case LOGICAL: + cout << "logical"; + break; + case NONE: + cout << "omitted"; + break; + default: + cout << "error "; + break; + } // switch + cout.width(7); + if (!isGpt) { + if (canBeLogical) + cout << " Y "; + else + cout << " "; + if (canBePrimary) + cout << " Y "; + else + cout << " "; + } // if + cout << "0x"; + cout.width(2); + cout.fill('0'); + cout << hex << (int) partitionType << dec << "\n"; +} // MBRPart::ShowData()
\ No newline at end of file diff --git a/mbrpart.h b/mbrpart.h new file mode 100644 index 0000000..4d84e7a --- /dev/null +++ b/mbrpart.h @@ -0,0 +1,111 @@ +/* + MBRPart class, part of GPT fdisk program family. + Copyright (C) 2011 Roderick W. Smith + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef MBRPART_H +#define MBRPART_H + +#include <stdint.h> + +#define MAX_HEADS 255 /* numbered 0 - 254 */ +#define MAX_SECSPERTRACK 63 /* numbered 1 - 63 */ +#define MAX_CYLINDERS 1024 /* numbered 0 - 1023 */ + +#define NONE 0 /* don't include partition when writing */ +#define PRIMARY 1 /* write partition as primary */ +#define LOGICAL 2 /* write partition as logical */ +#define EBR 4 /* sector is used as an EBR or MBR */ +#define INVALID 8 /* sector number is too large for disk */ + +using namespace std; + +// Data for a single MBR partition record +// Note that firstSector and lastSector are in CHS addressing, which +// splits the bits up in a weird way. +// On read or write of MBR entries, firstLBA is an absolute disk sector. +// On read of logical entries, it's relative to the EBR record for that +// partition. When writing EBR records, it's relative to the extended +// partition's start. +#pragma pack(1) +struct MBRRecord { + uint8_t status; + uint8_t firstSector[3]; + uint8_t partitionType; + uint8_t lastSector[3]; + uint32_t firstLBA; // see above + uint32_t lengthLBA; +}; // struct MBRRecord + +class MBRPart { +protected: + uint8_t status; + uint8_t firstSector[3]; + uint8_t partitionType; + uint8_t lastSector[3]; + uint32_t firstLBA; // see above + uint32_t lengthLBA; + int includeAs; // PRIMARY, LOGICAL, or NONE + int canBeLogical; + int canBePrimary; + static uint32_t numHeads; + static uint32_t numSecspTrack; + static uint64_t diskSize; + static uint32_t blockSize; + static int numInstances; + +public: + MBRPart(); + MBRPart(const MBRPart& other); + virtual ~MBRPart(); + virtual MBRPart& operator=(const MBRPart& orig); + virtual MBRPart& operator=(const struct MBRRecord& orig); + + // Set information on partitions or disks... + void SetGeometry(uint32_t heads, uint32_t sectors, uint64_t diskSize, uint32_t blockSize); + void Empty(void); + void SetStartLBA(uint64_t s); + void SetLengthLBA(uint64_t l); + void SetLocation(uint64_t start, uint64_t length); + int SetType(uint8_t typeCode, int isExtended = 0); + void SetStatus(uint8_t s) {status = s;} + void SetInclusion(int status = PRIMARY) {includeAs = status;} + void SetCanBeLogical(int c) {canBeLogical = c;} + void SetCanBePrimary(int c) {canBePrimary = c;} + void StoreInStruct(struct MBRRecord *theStruct); + + // Get information on partitions or disk.... + uint8_t GetType(void) {return partitionType;} + uint8_t GetStatus(void) {return status;} + uint64_t GetStartLBA(void) {return firstLBA;} + uint64_t GetLengthLBA(void) {return lengthLBA;} + uint64_t GetLastLBA(void) const; + uint8_t GetInclusion(void) {return includeAs;} + int CanBeLogical(void) {return canBeLogical;} + int CanBePrimary(void) {return canBePrimary;} + int DoTheyOverlap (const MBRPart& other); + + // Adjust information on partitions or disks... + void RecomputeCHS(void); + int LBAtoCHS(uint32_t lba, uint8_t * chs); + void ReverseByteOrder(void); + + // User I/O... + void ShowData(int isGpt); +}; // MBRPart + +#endif // MBRPART_H diff --git a/partnotes.cc b/partnotes.cc deleted file mode 100644 index a35f9c7..0000000 --- a/partnotes.cc +++ /dev/null @@ -1,625 +0,0 @@ -/* - partnotes.cc -- Class that takes notes on GPT partitions for purpose of MBR conversion - Copyright (C) 2010 Roderick W. Smith - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -*/ - -#include <iostream> -#include <stdio.h> -#include "partnotes.h" -#include "gpt.h" - -using namespace std; - -PartNotes::PartNotes() { - notes = NULL; - currentNote = NULL; - currentIndex = 0; - origTableSize = 0; - blockSize = 512; - dummyNote.active = 0; - dummyNote.origPartNum = MBR_EMPTY; - dummyNote.hexCode = 0xEE; - dummyNote.next = NULL; - dummyNote.spaceBefore = 0; - dummyNote.type = WILL_NOT_CONVERT; -} // PartNotes constructor - -// Destructor. Note that we do NOT delete the gptParts array, since we just -// store a pointer to an array that's allocated by the calling function. -PartNotes::~PartNotes() { - DeleteNotes(); -} // PartNotes destructor - -// Delete the partition notes.... -void PartNotes::DeleteNotes(void) { - struct PartInfo *nextNote; - - while (notes != NULL) { - nextNote = notes->next; - delete notes; - notes = nextNote; - } // while - notes = NULL; -} // PartNotes::DeleteNotes() - -/************************************************************************* - * * - * Begin functions that add data to the notes, either by whole notes * - * or in smaller units. By and large these functions perform little * - * or no error checking on the added data, so they can create completely * - * bogus layouts if used carelessly. * - * * - *************************************************************************/ - -// Add a single partition to the end of the linked list. -// Returns 1 on success, 0 on failures. -int PartNotes::AddToEnd(struct PartInfo *newOne) { - struct PartInfo *temp; - int allOK = 1; - - if (newOne != NULL) { - newOne->next = NULL; - if (notes == NULL) { - notes = newOne; - } else { - temp = notes; - while (temp->next != NULL) { - temp = temp->next; - } // while - temp->next = newOne; - } // if/else - } else allOK = 0; - return allOK; -} // PartNotes::AddToEnd() - -// Add a single partition to the start of the linked list. -// Returns 1 on success, 0 on failures. -int PartNotes::AddToStart(struct PartInfo *newOne) { - int allOK = 1; - - if (newOne != NULL) { - newOne->next = notes; - notes = newOne; - } else allOK = 0; - return allOK; -} // PartNotes::AddToStart() - -// Set the type of the partition to PRIMARY, LOGICAL, or WILL_NOT_CONVERT. -// If partNum is <0, sets type on first partition; if partNum > number -// of defined partitions, sets type on last partition; if notes list is -// NULL, does nothing. -void PartNotes::SetType(int partNum, int type) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - theNote->type = type; - } // if -} // PartNotes::SetType() - -// Set the MBR hex type to be used -void PartNotes::SetMbrHexType(int partNum, uint8_t type) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if ((type != 0x0f) && (type != 0x05) && (type != 0x85)) { - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - theNote->hexCode = type; - } // if - } else { - cout << "Refusing to set MBR hex code to one used for an extended partition!\n"; - } // if/else -} // PartNotes::SetMBRHexType() - -void PartNotes::ToggleActiveStatus(int partNum) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - if (theNote->active) - theNote->active = 0; - else - theNote->active = 0x80; - } // if -} // PartNotes::ToggleActiveStatus - - -/*************************************************************************** - * * - * The following functions retrieve data, either in whole PartInfo units * - * or in smaller chunks. Some functions perform computations and * - * comparisons that may require traversing the entire linked list, perhaps * - * multiple times. * - * * - ***************************************************************************/ - -// Reset currentNotes pointer to the start of the linked list and adjust -// currentIndex to 0. (Doesn't really retrieve data, but it should be -// called before most loops that employ PartNotes::GetNextInfo().) -void PartNotes::Rewind(void) { - currentNote = notes; - currentIndex = 0; -} // PartNotes::Rewind() - -// Retrieve the PartInfo structure pointed to by the currentNote pointer, -// then point currentNote to the next one in the linked list. -// Returns the number of the returned structure (counting from 0), -// or -1 if the end has been reached and it returns a dummy value -int PartNotes::GetNextInfo(struct PartInfo* info) { - if (currentNote != NULL) { - *info = *currentNote; - currentNote = currentNote->next; - currentIndex++; - return (currentIndex - 1); - } else return -1; -} // PartNotes::GetNextInfo - -// Count up the number of partitions that are flagged as either -// primary or logical -int PartNotes::GetNumParts() { - int num = 0; - struct PartInfo *theNote; - - theNote = notes; - while (theNote != NULL) { - if (((theNote->type == PRIMARY) || (theNote->type == LOGICAL))) - num++; - theNote = theNote->next; - } // while() - return num; -} // PartNotes::GetNumParts() - -// Count up the number of partitions that are flagged as MBR primary -// partitions and that have non-negative partition numbers. Note that -// this value can be greater than 4. -int PartNotes::GetNumPrimary() { - int num = 0; - struct PartInfo *theNote; - - theNote = notes; - while (theNote != NULL) { - if (theNote->type == PRIMARY) - num++; - theNote = theNote->next; - } // while() - return num; -} // PartNotes::GetNumPrimary() - -// Return the number of extended partitions required to house the -// partitions that are currently flagged as being logical. This -// number should be 0 or 1 to make a legal configuration, but this -// function will return higher values if the current configuration -// is illegal because it requires more than one extended partition. -int PartNotes::GetNumExtended() { - int num = 0, lastWasLogical = 0; - struct PartInfo *theNote; - - theNote = notes; - while (theNote != NULL) { - switch (theNote->type) { - case PRIMARY: - lastWasLogical = 0; - break; - case LOGICAL: - if (!lastWasLogical) - num++; - lastWasLogical = 1; - break; - case WILL_NOT_CONVERT: - break; // do nothing - } // switch - theNote = theNote->next; - } // while - return num; -} // PartNotes::GetNumExtended() - -// Count up the number of partitions that are flagged as MBR logical -// partitions. Note that these may be discontiguous, and so represent -// an illegal configuration... -int PartNotes::GetNumLogical() { - int num = 0; - struct PartInfo *theNote; - - theNote = notes; - while (theNote != NULL) { - if (theNote->type == LOGICAL) - num++; - theNote = theNote->next; - } // while() - return num; -} // PartNotes::GetNumLogical() - -// Return the partition type (PRIMARY, LOGICAL, or WILL_NOT_CONVERT) -// If partNum is <0, returns status of first partition; if partNum > -// number of defined partitions, returns status of last partition; -// if notes list is NULL, returns WILL_NOT_CONVERT. -int PartNotes::GetType(int partNum) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - return theNote->type; - } else { - return WILL_NOT_CONVERT; - } // if/else -} // PartNotes::GetType() - -// Return the scheduled MBR hex code -uint8_t PartNotes::GetMbrHexType(int partNum) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - return theNote->hexCode; - } else { - return 0x00; - } // if/else -} // PartNotes::GetMBRHexType() - -// Return the original partition number associated with this note, -1 if -// the notes list is empty, or the original partition number of the last -// partition if partNum is too high. -int PartNotes::GetOrigNum(int partNum) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - return theNote->origPartNum; - } else { - return -1; - } // if/else -} // PartNotes::GetOrigNum() - -// Return whether or not the partition is flagged as active (bootable) -int PartNotes::GetActiveStatus(int partNum) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - return theNote->active; - } else { - return 0; - } // if/else -} // PartNotes::GetActiveStatus() - -// Returns 1 if the partition can be a logical partition (ignoring whether this -// will make the set as a whole illegal), 0 if it must be a primary -int PartNotes::CanBeLogical(int partNum) { - int count = 0; - struct PartInfo *theNote; - - theNote = notes; - if (theNote != NULL) { - while ((count++ < partNum) && (theNote->next != NULL)) - theNote = theNote->next; - return theNote->spaceBefore; - } else { - return 0; - } // if/else -} // PartNotes::CanBeLogical() - -// Find the logical partition that begins the first extended -// partition, starting at start. -// Returns the number of logicals in that partition, or 0 if nothing -// is found. The start value is modified to point to the first -// logical partition in the extended partition (it's called by -// reference!). -int PartNotes::FindExtended(int &start) { - int length = 0, next = 0; - struct PartInfo *theNote; - - if ((notes != NULL) && (start >= 0)) { - theNote = notes; - while ((theNote->next != NULL) && ((next < start) || (theNote->type != LOGICAL))) { - theNote = theNote->next; - next++; - } // while() - start = next; - while ((theNote->next != NULL) && (theNote->type == LOGICAL)) { - length ++; - theNote = theNote->next; - } // while - } // if arrays exist - return length; -} // PartNotes::FindExtended() - -// Returns 1 if the set as a whole makes a legal MBR partition table -// (possibly with logicals), 0 if not -int PartNotes::IsLegal(void) { - int p, e, legalLogicals = 1; - struct PartInfo *theNote; - - p = GetNumPrimary(); - e = GetNumExtended(); - theNote = notes; - while (theNote != NULL) { - if ((!theNote->spaceBefore) && (theNote->type == LOGICAL)) - legalLogicals = 0; - theNote = theNote->next; - } // while - return (((p+e) <= 4) && (e <= 1) && legalLogicals); -} // PartNotes::IsLegal() - -/************************************************************************* - * * - * The following partitions manipulate the data in the quest to create a * - * legal MBR layout. * - * * - *************************************************************************/ - -// Remove duplicate partitions from the list. -void PartNotes::RemoveDuplicates(void) { - struct PartInfo *n1, *n2; - - n1 = notes; - while (n1 != NULL) { - n2 = n1->next; - while (n2 != NULL) { - if ((n1->firstLBA == n2->firstLBA) && (n1->lastLBA == n2->lastLBA)) { - n1->next = n2->next; - delete n2; - n2 = n1->next; - } else { - n2 = n2->next; - } // if/else - } // while (n2 != NULL) - n1 = n1->next; - } // while (n1 != NULL) -} // PartNotes::RemoveDuplicates() - -// Creates a legal mix of primaries and logicals, maximizing the number -// of included partitions. Also removes duplicates. -// Returns 1 if successful, 0 if not (if missing notes list, say) -int PartNotes::MakeItLegal(void) { - struct PartInfo *theNote, *lastPrimary, *firstPart; - - if (notes == NULL) - return 0; - - RemoveDuplicates(); - - if (!IsLegal()) { - cout << "Isn't legal!\n"; - // Start by eliminating or converting excessive extended partitions... - while (GetNumExtended() > 1) - TrimSmallestExtended(); - // If that was insufficient, cut primary partitions... - lastPrimary = notes; - while (!IsLegal() && (lastPrimary != NULL)) { - lastPrimary = NULL; - theNote = notes; - do { - if (theNote->type == PRIMARY) - lastPrimary = theNote; - theNote = theNote->next; - } while (theNote != NULL); - if (lastPrimary != NULL) - lastPrimary->type = WILL_NOT_CONVERT; - } // if - } // if - - // If four or fewer partitions were converted, make them all primaries - if ((GetNumPrimary() + GetNumLogical()) <= 4) { - theNote = notes; - do { - if (theNote->type == LOGICAL) - theNote->type = PRIMARY; - theNote = theNote->next; - } while (theNote != NULL); - } // if - - // Try to make the first partition a primary... - if ((GetNumExtended() + GetNumPrimary()) < 4) { - theNote = notes; - firstPart = notes; - while ((theNote != NULL) && (firstPart != NULL)) { - if ((theNote->firstLBA < firstPart->firstLBA) && (theNote->type != WILL_NOT_CONVERT)) - firstPart = theNote; - theNote = theNote->next; - }; - if (firstPart->spaceBefore) - firstPart->type = PRIMARY; - } // if - - return IsLegal(); -} // PartNotes::MakeItLegal() - -// Change the type flag in the notes array for all the partitions associated -// with the smallest extended partition to WILL_NOT_CONVERT or (if possible) -// PRIMARY -void PartNotes::TrimSmallestExtended() { - struct ExtendedInfo *extendeds; - int i, numExtended, shortestNum, shortestIndex = -1; - struct PartInfo *theNote; - - if (notes != NULL) { - numExtended = GetNumExtended(); - extendeds = new struct ExtendedInfo[numExtended]; - - // Find the start and number of partitions in each extended partition.... - for (i = 0; i < numExtended; i++) { - if (i == 0) - extendeds[i].startNum = 0; - else - extendeds[i].startNum = extendeds[i - 1].startNum + extendeds[i - 1].numLogicals; - extendeds[i].numLogicals = FindExtended(extendeds[i].startNum); - } // for - - // Find the smallest extended partition.... - shortestNum = origTableSize + 1; - for (i = 0; i < numExtended; i++) { - if (extendeds[i].numLogicals < shortestNum) { - shortestNum = extendeds[i].numLogicals; - shortestIndex = extendeds[i].startNum; - } // if - } // for - - // Now flag its partitions as PRIMARY (if possible) or - // WILL_NOT_CONVERT - theNote = notes; - i = 0; - while ((i++ < shortestIndex) && (theNote->next != NULL)) - theNote = theNote->next; - do { - if (GetNumPrimary() < 3) - theNote->type = PRIMARY; - else - theNote->type = WILL_NOT_CONVERT; - theNote = theNote->next; - } while ((i++ < shortestNum + shortestIndex) && (theNote != NULL)); - - delete[] extendeds; - } // if -} // PartNotes::TrimSmallestExtended - - -/************************************************************************* - * * - * Interact with users, presenting data and/or collecting responses. May * - * change data with error detection and correction. * - * * - *************************************************************************/ - -// Display summary information for the user -void PartNotes::ShowSummary(void) { - cerr << "Program is calling PartNotes::ShowSummary(); this is a virtual base function,\n" - << "and should never be called.\n"; -} // PartNotes::ShowSummary() - -// Interact with the user to create a change in the specified -// partition. -// Returns 1 if successful, 0 if not. Note that aborting the -// change counts as successful; 0 should be returned only in -// case of dire bugs. -int PartNotes::MakeChange(int partNum) { - int allOK = 1; - int type = 0; - char line[255], command; - - if (notes != NULL) { - cout << "What do you want to do?\n"; - cout << " a - toggle active flag\n"; - switch (GetType(partNum)) { - case PRIMARY: - cout << " d - drop partition from MBR\n"; - cout << " l - convert partition to logical\n"; - break; - case LOGICAL: - cout << " d - drop partition from MBR\n"; - cout << " p - convert partition to primary\n"; - break; - case WILL_NOT_CONVERT: - cout << " p - add partition as primary\n"; - cout << " l - add partition as logical\n"; - break; - } // switch - cout << " t - change MBR type code\n"; - cout << "Action: "; - if (!fgets(line, 255, stdin)) { - cerr << "Critical error! Failed fgets() in PartNotes::MakeChange()!\n"; - exit(1); - } // if - sscanf(line, "%c", &command); - switch (command) { - case 'a': case 'A': - ToggleActiveStatus(partNum); - break; - case 'd': case 'D': - allOK = ChangeType(partNum, WILL_NOT_CONVERT); - break; - case 'l': case 'L': - allOK = ChangeType(partNum, LOGICAL); - break; - case 'p': case 'P': - allOK = ChangeType(partNum, PRIMARY); - break; - case 't': case 'T': - while (type == 0) { - cout << "Enter a 2-byte hexadecimal MBR type code: "; - if (!fgets(line, 255, stdin)) { - cerr << "Critical error! Failed fgets() in PartNotes::MakeChange()\n"; - exit(1); - } // if - sscanf(line, "%x", &type); - } // while - SetMbrHexType(partNum, (uint8_t) type); - break; - default: - cout << "Unrecognized command; making no change.\n"; - break; - } // switch - } else allOK = 0; // if - return allOK; -} // PartNotes::MakeChange() - -// Turn the partition into the specified type, if this is legal. -// Returns 1 unless there's a dire bug. -int PartNotes::ChangeType(int partNum, int newType) { - int origType, allOK = 1; - char line[255]; - - if ((notes != NULL) && IsLegal()) { - origType = GetType(partNum); - SetType(partNum, newType); - if (!IsLegal()) { - cout << "The requested change is not possible.\n"; - if (newType == LOGICAL) { - if (!CanBeLogical(partNum)) - cout << "At least one free sector must exist before each logical partition.\n"; - else - cout << "All logical partitions must be contiguous.\n"; - } // if - if ((newType == PRIMARY) && (GetNumPrimary() + GetNumExtended()) > 4) - cout << "You can have only four primary partitions (all logical partitions " - << "count as one\nprimary partition).\n"; - if ((newType == PRIMARY) && (GetNumExtended()) > 1) - cout << "Logical partitions must form a single contiguous group.\n"; - cout << "\nYou may be able to achieve your desired goal by making changes in " - << "another\norder, such as deleting partitions before changing others' " - << "types.\n"; - cout << "\nReverting change.\nPress <Enter> to continue: "; - if (!fgets(line, 255, stdin)) { - cerr << "Critical error! Failed fgets() in PartNotes::ChangeType()\n"; - exit(1); - } // if - SetType(partNum, origType); - } // if - } else allOK = 0; // if - return allOK; -} // PartNotes::ChangeType() diff --git a/partnotes.h b/partnotes.h deleted file mode 100644 index 750b75f..0000000 --- a/partnotes.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - partnotes.h -- Class that takes notes on GPT partitions for purpose of MBR conversion - Copyright (C) 2010-2011 Roderick W. Smith - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -*/ - -#ifndef __PARTNOTES_H -#define __PARTNOTES_H - -#include <stdint.h> -#include <sys/types.h> - -using namespace std; - -#define WILL_NOT_CONVERT 0 -#define PRIMARY 1 -#define LOGICAL 2 - -// Data structure used in GPT-to-MBR conversions; holds pointer to GPT -// partition number, start and end sectors, and a few MBR-specific details -struct PartInfo { - int origPartNum; - int spaceBefore; // boolean; if 1, can theoretically become a logical part. - int active; // boolean - int type; // WILL_NOT_CONVERT, PRIMARY, or LOGICAL - uint64_t firstLBA; - uint64_t lastLBA; - unsigned int hexCode; - struct PartInfo *next; -}; - -struct ExtendedInfo { - int startNum; - int numLogicals; -}; - -class PartNotes { - protected: - struct PartInfo dummyNote; - struct PartInfo *notes; - struct PartInfo *currentNote; - int currentIndex; - int blockSize; - int origTableSize; - - void DeleteNotes(void); - - public: - PartNotes(); - ~PartNotes(); - - // Add partition notes (little or no error checking) -// int PassPartitions(GPTPart *parts, GPTData *gpt, int num, int blockSize); - int AddToEnd(struct PartInfo* newOne); - int AddToStart(struct PartInfo* newOne); - void SetType(int partNum, int type); // type is PRIMARY, LOGICAL, or WILL_NOT_CONVERT - void SetMbrHexType(int partNum, uint8_t type); - void ToggleActiveStatus(int partNum); - - // Retrieve data or metadata - void Rewind(void); - int GetNextInfo(struct PartInfo * info); - int GetNumParts(); - int GetNumPrimary(); - int GetNumExtended(); - int GetNumLogical(); - int GetType(int partNum); - uint8_t GetMbrHexType(int i); - int GetOrigNum(int partNum); - int GetActiveStatus(int partNum); - int CanBeLogical(int partNum); // returns boolean - int FindExtended(int &start); - int IsLegal(void); // returns Boolean - - // Manipulate data or metadata - void RemoveDuplicates(void); - int MakeItLegal(void); - void TrimSmallestExtended(void); - - // Interact with users, possibly changing data with error handling - virtual void ShowSummary(void); - int MakeChange(int partNum); - int ChangeType(int partNum, int newType); -}; - -#endif // __PARTNOTES_H |