5 Star 2 Fork 20

OpenHarmony/third_party_gptfdisk

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
basicmbr.cc 58.77 KB
一键复制 编辑 原始数据 按行查看 历史
xlfeng 提交于 2022-06-09 14:39 . Updated version to 1.0.9
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672
/* basicmbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
data. */
/* Initial coding by Rod Smith, January to February, 2009 */
/* This program is copyright (c) 2009-2013 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
#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <errno.h>
#include <iostream>
#include <algorithm>
#include "mbr.h"
#include "support.h"
using namespace std;
/****************************************
* *
* MBRData class and related structures *
* *
****************************************/
BasicMBRData::BasicMBRData(void) {
blockSize = SECTOR_SIZE;
diskSize = 0;
device = "";
state = invalid;
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL;
canDeleteMyDisk = 0;
// memset(&EbrLocations, 0, MAX_MBR_PARTS * sizeof(uint32_t));
EmptyMBR();
} // BasicMBRData default constructor
BasicMBRData::BasicMBRData(const BasicMBRData & orig) {
int i;
if (&orig != this) {
memcpy(code, orig.code, 440);
diskSignature = orig.diskSignature;
nulls = orig.nulls;
MBRSignature = orig.MBRSignature;
blockSize = orig.blockSize;
diskSize = orig.diskSize;
numHeads = orig.numHeads;
numSecspTrack = orig.numSecspTrack;
canDeleteMyDisk = orig.canDeleteMyDisk;
device = orig.device;
state = orig.state;
myDisk = new DiskIO;
if (myDisk == NULL) {
cerr << "Unable to allocate memory in BasicMBRData copy constructor! Terminating!\n";
exit(1);
} // if
if (orig.myDisk != NULL)
myDisk->OpenForRead(orig.myDisk->GetName());
for (i = 0; i < MAX_MBR_PARTS; i++) {
partitions[i] = orig.partitions[i];
} // for
} // if
} // BasicMBRData copy constructor
BasicMBRData::BasicMBRData(string filename) {
blockSize = SECTOR_SIZE;
diskSize = 0;
device = filename;
state = invalid;
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL;
canDeleteMyDisk = 0;
// memset(&EbrLocations, 0, MAX_MBR_PARTS * sizeof(uint32_t));
// Try to read the specified partition table, but if it fails....
if (!ReadMBRData(filename)) {
EmptyMBR();
device = "";
} // if
} // BasicMBRData(string filename) constructor
// Free space used by myDisk only if that's OK -- sometimes it will be
// copied from an outside source, in which case that source should handle
// it!
BasicMBRData::~BasicMBRData(void) {
if (canDeleteMyDisk)
delete myDisk;
} // BasicMBRData destructor
// Assignment operator -- copy entire set of MBR data.
BasicMBRData & BasicMBRData::operator=(const BasicMBRData & orig) {
int i;
if (&orig != this) {
memcpy(code, orig.code, 440);
diskSignature = orig.diskSignature;
nulls = orig.nulls;
MBRSignature = orig.MBRSignature;
blockSize = orig.blockSize;
diskSize = orig.diskSize;
numHeads = orig.numHeads;
numSecspTrack = orig.numSecspTrack;
canDeleteMyDisk = orig.canDeleteMyDisk;
device = orig.device;
state = orig.state;
myDisk = new DiskIO;
if (myDisk == NULL) {
cerr << "Unable to allocate memory in BasicMBRData::operator=()! Terminating!\n";
exit(1);
} // if
if (orig.myDisk != NULL)
myDisk->OpenForRead(orig.myDisk->GetName());
for (i = 0; i < MAX_MBR_PARTS; i++) {
partitions[i] = orig.partitions[i];
} // for
} // if
return *this;
} // BasicMBRData::operator=()
/**********************
* *
* Disk I/O functions *
* *
**********************/
// Read data from MBR. Returns 1 if read was successful (even if the
// data isn't a valid MBR), 0 if the read failed.
int BasicMBRData::ReadMBRData(const string & deviceFilename) {
int allOK;
if (myDisk == NULL) {
myDisk = new DiskIO;
if (myDisk == NULL) {
cerr << "Unable to allocate memory in BasicMBRData::ReadMBRData()! Terminating!\n";
exit(1);
} // if
canDeleteMyDisk = 1;
} // if
if (myDisk->OpenForRead(deviceFilename)) {
allOK = ReadMBRData(myDisk);
} else {
allOK = 0;
} // if
if (allOK)
device = deviceFilename;
return allOK;
} // BasicMBRData::ReadMBRData(const string & deviceFilename)
// Read data from MBR. If checkBlockSize == 1 (the default), the block
// size is checked; otherwise it's set to the default (512 bytes).
// Note that any extended partition(s) present will be omitted from
// in the partitions[] array; these partitions must be re-created when
// the partition table is saved in MBR format.
int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
int allOK = 1, i, logicalNum = 3;
int err = 1;
TempMBR tempMBR;
if ((myDisk != NULL) && (myDisk != theDisk) && (canDeleteMyDisk)) {
delete myDisk;
canDeleteMyDisk = 0;
} // if
myDisk = theDisk;
// Empty existing MBR data, including the logical partitions...
EmptyMBR(0);
if (myDisk->Seek(0))
if (myDisk->Read(&tempMBR, 512))
err = 0;
if (err) {
cerr << "Problem reading disk in BasicMBRData::ReadMBRData()!\n";
} else {
for (i = 0; i < 440; i++)
code[i] = tempMBR.code[i];
diskSignature = tempMBR.diskSignature;
nulls = tempMBR.nulls;
for (i = 0; i < 4; i++) {
partitions[i] = tempMBR.partitions[i];
if (partitions[i].GetLengthLBA() > 0)
partitions[i].SetInclusion(PRIMARY);
} // for i... (reading all four partitions)
MBRSignature = tempMBR.MBRSignature;
ReadCHSGeom();
// Reverse the byte order, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes(&diskSignature, 4);
ReverseBytes(&nulls, 2);
ReverseBytes(&MBRSignature, 2);
for (i = 0; i < 4; i++) {
partitions[i].ReverseByteOrder();
} // for
} // if
if (MBRSignature != MBR_SIGNATURE) {
allOK = 0;
state = invalid;
} // if
// Find disk size
diskSize = myDisk->DiskSize(&err);
// Find block size
if (checkBlockSize) {
blockSize = myDisk->GetBlockSize();
} // if (checkBlockSize)
// Load logical partition data, if any is found....
if (allOK) {
for (i = 0; i < 4; i++) {
if ((partitions[i].GetType() == 0x05) || (partitions[i].GetType() == 0x0f)
|| (partitions[i].GetType() == 0x85)) {
// Found it, so call a function to load everything from them....
logicalNum = ReadLogicalParts(partitions[i].GetStartLBA(), abs(logicalNum) + 1);
if (logicalNum < 0) {
cerr << "Error reading logical partitions! List may be truncated!\n";
} // if maxLogicals valid
DeletePartition(i);
} // if primary partition is extended
} // for primary partition loop
if (allOK) { // Loaded logicals OK
state = mbr;
} else {
state = invalid;
} // if
} // if
// Check to see if it's in GPT format....
if (allOK) {
for (i = 0; i < 4; i++) {
if (partitions[i].GetType() == UINT8_C(0xEE)) {
state = gpt;
} // if
} // for
} // if
// If there's an EFI GPT partition, look for other partition types,
// to flag as hybrid
if (state == gpt) {
for (i = 0 ; i < 4; i++) {
if ((partitions[i].GetType() != UINT8_C(0xEE)) &&
(partitions[i].GetType() != UINT8_C(0x00)))
state = hybrid;
if (logicalNum != 3)
cerr << "Warning! MBR Logical partitions found on a hybrid MBR disk! This is an\n"
<< "EXTREMELY dangerous configuration!\n\a";
} // for
} // if (hybrid detection code)
} // no initial error
return allOK;
} // BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize)
// This is a function to read all the logical partitions, following the
// logical partition linked list from the disk and storing the basic data in the
// partitions[] array. Returns last index to partitions[] used, or -1 times the
// that index if there was a problem. (Some problems can leave valid logical
// partition data.)
// Parameters:
// extendedStart = LBA of the start of the extended partition
// partNum = number of first partition in extended partition (normally 4).
int BasicMBRData::ReadLogicalParts(uint64_t extendedStart, int partNum) {
struct TempMBR ebr;
int i, another = 1, allOK = 1;
uint8_t ebrType;
uint64_t offset;
uint64_t EbrLocations[MAX_MBR_PARTS];
offset = extendedStart;
memset(&EbrLocations, 0, MAX_MBR_PARTS * sizeof(uint64_t));
while (another && (partNum < MAX_MBR_PARTS) && (partNum >= 0) && (allOK > 0)) {
for (i = 0; i < MAX_MBR_PARTS; i++) {
if (EbrLocations[i] == offset) { // already read this one; infinite logical partition loop!
cerr << "Logical partition infinite loop detected! This is being corrected.\n";
allOK = -1;
if (partNum > 0) //don't go negative
partNum -= 1;
} // if
} // for
EbrLocations[partNum] = offset;
if (myDisk->Seek(offset) == 0) { // seek to EBR record
cerr << "Unable to seek to " << offset << "! Aborting!\n";
allOK = -1;
}
if (myDisk->Read(&ebr, 512) != 512) { // Load the data....
cerr << "Error seeking to or reading logical partition data from " << offset
<< "!\nSome logical partitions may be missing!\n";
allOK = -1;
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
ReverseBytes(&ebr.MBRSignature, 2);
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
} // if/else/if
if (ebr.MBRSignature != MBR_SIGNATURE) {
allOK = -1;
cerr << "EBR signature for logical partition invalid; read 0x";
cerr.fill('0');
cerr.width(4);
cerr.setf(ios::uppercase);
cerr << hex << ebr.MBRSignature << ", but should be 0x";
cerr.width(4);
cerr << MBR_SIGNATURE << dec << "\n";
cerr.fill(' ');
} // if
if ((partNum >= 0) && (partNum < MAX_MBR_PARTS) && (allOK > 0)) {
// Sometimes an EBR points directly to another EBR, rather than defining
// a logical partition and then pointing to another EBR. Thus, we skip
// the logical partition when this is the case....
ebrType = ebr.partitions[0].partitionType;
if ((ebrType == 0x05) || (ebrType == 0x0f) || (ebrType == 0x85)) {
cout << "EBR points to an EBR!\n";
offset = extendedStart + ebr.partitions[0].firstLBA;
} else {
// Copy over the basic data....
partitions[partNum] = ebr.partitions[0];
// Adjust the start LBA, since it's encoded strangely....
partitions[partNum].SetStartLBA(ebr.partitions[0].firstLBA + offset);
partitions[partNum].SetInclusion(LOGICAL);
// Find the next partition (if there is one)
if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum < (MAX_MBR_PARTS - 1))) {
offset = extendedStart + ebr.partitions[1].firstLBA;
partNum++;
} else {
another = 0;
} // if another partition
} // if/else
} // if
} // while()
return (partNum * allOK);
} // BasicMBRData::ReadLogicalPart()
// Write the MBR data to the default defined device. This writes both the
// MBR itself and any defined logical partitions, provided there's an
// MBR extended partition.
int BasicMBRData::WriteMBRData(void) {
int allOK;
if (myDisk != NULL) {
if (myDisk->OpenForWrite() != 0) {
allOK = WriteMBRData(myDisk);
cout << "Done writing data!\n";
} else {
allOK = 0;
} // if/else
myDisk->Close();
} else allOK = 0;
return allOK;
} // BasicMBRData::WriteMBRData(void)
// Save the MBR data to a file. This writes both the
// MBR itself and any defined logical partitions.
int BasicMBRData::WriteMBRData(DiskIO *theDisk) {
int i, j, partNum, next, allOK, moreLogicals = 0;
uint64_t extFirstLBA = 0;
uint64_t writeEbrTo; // 64-bit because we support extended in 2-4TiB range
TempMBR tempMBR;
allOK = CreateExtended();
if (allOK) {
// First write the main MBR data structure....
memcpy(tempMBR.code, code, 440);
tempMBR.diskSignature = diskSignature;
tempMBR.nulls = nulls;
tempMBR.MBRSignature = MBRSignature;
for (i = 0; i < 4; i++) {
partitions[i].StoreInStruct(&tempMBR.partitions[i]);
if (partitions[i].GetType() == 0x0f) {
extFirstLBA = partitions[i].GetStartLBA();
moreLogicals = 1;
} // if
} // for i...
} // if
allOK = allOK && WriteMBRData(tempMBR, theDisk, 0);
// Set up tempMBR with some constant data for logical partitions...
tempMBR.diskSignature = 0;
for (i = 2; i < 4; i++) {
tempMBR.partitions[i].firstLBA = tempMBR.partitions[i].lengthLBA = 0;
tempMBR.partitions[i].partitionType = 0x00;
for (j = 0; j < 3; j++) {
tempMBR.partitions[i].firstSector[j] = 0;
tempMBR.partitions[i].lastSector[j] = 0;
} // for j
} // for i
partNum = FindNextInUse(4);
writeEbrTo = (uint64_t) extFirstLBA;
// Write logicals...
while (allOK && moreLogicals && (partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
partitions[partNum].StoreInStruct(&tempMBR.partitions[0]);
tempMBR.partitions[0].firstLBA = 1;
// tempMBR.partitions[1] points to next EBR or terminates EBR linked list...
next = FindNextInUse(partNum + 1);
if ((next < MAX_MBR_PARTS) && (next > 0) && (partitions[next].GetStartLBA() > 0)) {
tempMBR.partitions[1].partitionType = 0x0f;
tempMBR.partitions[1].firstLBA = (uint32_t) (partitions[next].GetStartLBA() - extFirstLBA - 1);
tempMBR.partitions[1].lengthLBA = (uint32_t) (partitions[next].GetLengthLBA() + 1);
LBAtoCHS((uint64_t) tempMBR.partitions[1].firstLBA,
(uint8_t *) &tempMBR.partitions[1].firstSector);
LBAtoCHS(tempMBR.partitions[1].lengthLBA - extFirstLBA,
(uint8_t *) &tempMBR.partitions[1].lastSector);
} else {
tempMBR.partitions[1].partitionType = 0x00;
tempMBR.partitions[1].firstLBA = 0;
tempMBR.partitions[1].lengthLBA = 0;
moreLogicals = 0;
} // if/else
allOK = WriteMBRData(tempMBR, theDisk, writeEbrTo);
writeEbrTo = (uint64_t) tempMBR.partitions[1].firstLBA + (uint64_t) extFirstLBA;
partNum = next;
} // while
DeleteExtendedParts();
return allOK;
} // BasicMBRData::WriteMBRData(DiskIO *theDisk)
int BasicMBRData::WriteMBRData(const string & deviceFilename) {
device = deviceFilename;
return WriteMBRData();
} // BasicMBRData::WriteMBRData(const string & deviceFilename)
// Write a single MBR record to the specified sector. Used by the like-named
// function to write both the MBR and multiple EBR (for logical partition)
// records.
// Returns 1 on success, 0 on failure
int BasicMBRData::WriteMBRData(struct TempMBR & mbr, DiskIO *theDisk, uint64_t sector) {
int i, allOK;
// Reverse the byte order, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes(&mbr.diskSignature, 4);
ReverseBytes(&mbr.nulls, 2);
ReverseBytes(&mbr.MBRSignature, 2);
for (i = 0; i < 4; i++) {
ReverseBytes(&mbr.partitions[i].firstLBA, 4);
ReverseBytes(&mbr.partitions[i].lengthLBA, 4);
} // for
} // if
// Now write the data structure...
allOK = theDisk->OpenForWrite();
if (allOK && theDisk->Seek(sector)) {
if (theDisk->Write(&mbr, 512) != 512) {
allOK = 0;
cerr << "Error " << errno << " when saving MBR!\n";
} // if
} else {
allOK = 0;
cerr << "Error " << errno << " when seeking to MBR to write it!\n";
} // if/else
theDisk->Close();
// Reverse the byte order back, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes(&mbr.diskSignature, 4);
ReverseBytes(&mbr.nulls, 2);
ReverseBytes(&mbr.MBRSignature, 2);
for (i = 0; i < 4; i++) {
ReverseBytes(&mbr.partitions[i].firstLBA, 4);
ReverseBytes(&mbr.partitions[i].lengthLBA, 4);
} // for
}// if
return allOK;
} // BasicMBRData::WriteMBRData(uint64_t sector)
// Set a new disk device; used in copying one disk's partition
// table to another disk.
void BasicMBRData::SetDisk(DiskIO *theDisk) {
int err;
myDisk = theDisk;
diskSize = theDisk->DiskSize(&err);
canDeleteMyDisk = 0;
ReadCHSGeom();
} // BasicMBRData::SetDisk()
/********************************************
* *
* Functions that display data for the user *
* *
********************************************/
// Show the MBR data to the user, up to the specified maximum number
// of partitions....
void BasicMBRData::DisplayMBRData(void) {
int i;
cout << "\nDisk size is " << diskSize << " sectors ("
<< BytesToIeee(diskSize, blockSize) << ")\n";
cout << "MBR disk identifier: 0x";
cout.width(8);
cout.fill('0');
cout.setf(ios::uppercase);
cout << hex << diskSignature << dec << "\n";
cout << "MBR partitions:\n\n";
if ((state == gpt) || (state == hybrid)) {
cout << "Number Boot Start Sector End Sector Status Code\n";
} else {
cout << " Can Be Can Be\n";
cout << "Number Boot Start Sector End Sector Status Logical Primary Code\n";
UpdateCanBeLogical();
} //
for (i = 0; i < MAX_MBR_PARTS; i++) {
if (partitions[i].GetLengthLBA() != 0) {
cout.fill(' ');
cout.width(4);
cout << i + 1 << " ";
partitions[i].ShowData((state == gpt) || (state == hybrid));
} // if
cout.fill(' ');
} // for
} // BasicMBRData::DisplayMBRData()
// Displays the state, as a word, on stdout. Used for debugging & to
// tell the user about the MBR state when the program launches....
void BasicMBRData::ShowState(void) {
switch (state) {
case invalid:
cout << " MBR: not present\n";
break;
case gpt:
cout << " MBR: protective\n";
break;
case hybrid:
cout << " MBR: hybrid\n";
break;
case mbr:
cout << " MBR: MBR only\n";
break;
default:
cout << "\a MBR: unknown -- bug!\n";
break;
} // switch
} // BasicMBRData::ShowState()
/************************
* *
* GPT Checks and fixes *
* *
************************/
// Perform a very rudimentary check for GPT data on the disk; searches for
// the GPT signature in the main and backup metadata areas.
// Returns 0 if GPT data not found, 1 if main data only is found, 2 if
// backup only is found, 3 if both main and backup data are found, and
// -1 if a disk error occurred.
int BasicMBRData::CheckForGPT(void) {
int retval = 0, err;
char signature1[9], signature2[9];
if (myDisk != NULL) {
if (myDisk->OpenForRead() != 0) {
if (myDisk->Seek(1)) {
myDisk->Read(signature1, 8);
signature1[8] = '\0';
} else retval = -1;
if (myDisk->Seek(myDisk->DiskSize(&err) - 1)) {
myDisk->Read(signature2, 8);
signature2[8] = '\0';
} else retval = -1;
if ((retval >= 0) && (strcmp(signature1, "EFI PART") == 0))
retval += 1;
if ((retval >= 0) && (strcmp(signature2, "EFI PART") == 0))
retval += 2;
} else {
retval = -1;
} // if/else
myDisk->Close();
} else retval = -1;
return retval;
} // BasicMBRData::CheckForGPT()
// Blanks the 2nd (sector #1, numbered from 0) and last sectors of the disk,
// but only if GPT data are verified on the disk, and only for the sector(s)
// with GPT signatures.
// Returns 1 if operation completes successfully, 0 if not (returns 1 if
// no GPT data are found on the disk).
int BasicMBRData::BlankGPTData(void) {
int allOK = 1, err;
uint8_t blank[512];
memset(blank, 0, 512);
switch (CheckForGPT()) {
case -1:
allOK = 0;
break;
case 0:
break;
case 1:
if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
if (!((myDisk->Seek(1)) && (myDisk->Write(blank, 512) == 512)))
allOK = 0;
myDisk->Close();
} else allOK = 0;
break;
case 2:
if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
if (!((myDisk->Seek(myDisk->DiskSize(&err) - 1)) &&
(myDisk->Write(blank, 512) == 512)))
allOK = 0;
myDisk->Close();
} else allOK = 0;
break;
case 3:
if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
if (!((myDisk->Seek(1)) && (myDisk->Write(blank, 512) == 512)))
allOK = 0;
if (!((myDisk->Seek(myDisk->DiskSize(&err) - 1)) &&
(myDisk->Write(blank, 512) == 512)))
allOK = 0;
myDisk->Close();
} else allOK = 0;
break;
default:
break;
} // switch()
return allOK;
} // BasicMBRData::BlankGPTData
/*********************************************************************
* *
* Functions that set or get disk metadata (CHS geometry, disk size, *
* etc.) *
* *
*********************************************************************/
// Read the CHS geometry using OS calls, or if that fails, set to
// the most common value for big disks (255 heads, 63 sectors per
// track, & however many cylinders that computes to).
void BasicMBRData::ReadCHSGeom(void) {
int err;
numHeads = myDisk->GetNumHeads();
numSecspTrack = myDisk->GetNumSecsPerTrack();
diskSize = myDisk->DiskSize(&err);
blockSize = myDisk->GetBlockSize();
partitions[0].SetGeometry(numHeads, numSecspTrack, diskSize, blockSize);
} // BasicMBRData::ReadCHSGeom()
// Find the low and high used partition numbers (numbered from 0).
// Return value is the number of partitions found. Note that the
// *low and *high values are both set to 0 when no partitions
// are found, as well as when a single partition in the first
// position exists. Thus, the return value is the only way to
// tell when no partitions exist.
int BasicMBRData::GetPartRange(uint32_t *low, uint32_t *high) {
uint32_t i;
int numFound = 0;
*low = MAX_MBR_PARTS + 1; // code for "not found"
*high = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if (partitions[i].GetStartLBA() != UINT32_C(0)) { // it exists
*high = i; // since we're counting up, set the high value
// Set the low value only if it's not yet found...
if (*low == (MAX_MBR_PARTS + 1))
*low = i;
numFound++;
} // if
} // for
// Above will leave *low pointing to its "not found" value if no partitions
// are defined, so reset to 0 if this is the case....
if (*low == (MAX_MBR_PARTS + 1))
*low = 0;
return numFound;
} // GPTData::GetPartRange()
// Converts 64-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 BasicMBRData::LBAtoCHS(uint64_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 >= ((uint64_t) 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 / (uint64_t) (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 & UINT64_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);
} // BasicMBRData::LBAtoCHS()
// Look for overlapping partitions. Also looks for a couple of non-error
// conditions that the user should be told about.
// Returns the number of problems found
int BasicMBRData::FindOverlaps(void) {
int i, j, numProbs = 0, numEE = 0, ProtectiveOnOne = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
for (j = i + 1; j < MAX_MBR_PARTS; j++) {
if ((partitions[i].GetInclusion() != NONE) && (partitions[j].GetInclusion() != NONE) &&
(partitions[i].DoTheyOverlap(partitions[j]))) {
numProbs++;
cout << "\nProblem: MBR partitions " << i + 1 << " and " << j + 1
<< " overlap!\n";
} // if
} // for (j...)
if (partitions[i].GetType() == 0xEE) {
numEE++;
if (partitions[i].GetStartLBA() == 1)
ProtectiveOnOne = 1;
} // if
} // for (i...)
if (numEE > 1)
cout << "\nCaution: More than one 0xEE MBR partition found. This can cause problems\n"
<< "in some OSes.\n";
if (!ProtectiveOnOne && (numEE > 0))
cout << "\nWarning: 0xEE partition doesn't start on sector 1. This can cause "
<< "problems\nin some OSes.\n";
return numProbs;
} // BasicMBRData::FindOverlaps()
// Returns the number of primary partitions, including the extended partition
// required to hold any logical partitions found.
int BasicMBRData::NumPrimaries(void) {
int i, numPrimaries = 0, logicalsFound = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if (partitions[i].GetLengthLBA() > 0) {
if (partitions[i].GetInclusion() == PRIMARY)
numPrimaries++;
if (partitions[i].GetInclusion() == LOGICAL)
logicalsFound = 1;
} // if
} // for
return (numPrimaries + logicalsFound);
} // BasicMBRData::NumPrimaries()
// Returns the number of logical partitions.
int BasicMBRData::NumLogicals(void) {
int i, numLogicals = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if (partitions[i].GetInclusion() == LOGICAL)
numLogicals++;
} // for
return numLogicals;
} // BasicMBRData::NumLogicals()
// Returns the number of partitions (primaries plus logicals), NOT including
// the extended partition required to house the logicals.
int BasicMBRData::CountParts(void) {
int i, num = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].GetInclusion() == LOGICAL) ||
(partitions[i].GetInclusion() == PRIMARY))
num++;
} // for
return num;
} // BasicMBRData::CountParts()
// Updates the canBeLogical and canBePrimary flags for all the partitions.
void BasicMBRData::UpdateCanBeLogical(void) {
int i, j, sectorBefore, numPrimaries, numLogicals, usedAsEBR;
uint64_t firstLogical, lastLogical, lStart, pStart;
numPrimaries = NumPrimaries();
numLogicals = NumLogicals();
firstLogical = FirstLogicalLBA() - 1;
lastLogical = LastLogicalLBA();
for (i = 0; i < MAX_MBR_PARTS; i++) {
usedAsEBR = (SectorUsedAs(partitions[i].GetLastLBA()) == EBR);
if (usedAsEBR) {
partitions[i].SetCanBeLogical(0);
partitions[i].SetCanBePrimary(0);
} else if (partitions[i].GetLengthLBA() > 0) {
// First determine if it can be logical....
sectorBefore = SectorUsedAs(partitions[i].GetStartLBA() - 1);
lStart = partitions[i].GetStartLBA(); // start of potential logical part.
if ((lastLogical > 0) &&
((sectorBefore == EBR) || (sectorBefore == NONE))) {
// Assume it can be logical, then search for primaries that make it
// not work and, if found, flag appropriately.
partitions[i].SetCanBeLogical(1);
for (j = 0; j < MAX_MBR_PARTS; j++) {
if ((i != j) && (partitions[j].GetInclusion() == PRIMARY)) {
pStart = partitions[j].GetStartLBA();
if (((pStart < lStart) && (firstLogical < pStart)) ||
((pStart > lStart) && (firstLogical > pStart))) {
partitions[i].SetCanBeLogical(0);
} // if/else
} // if
} // for
} else {
if ((sectorBefore != EBR) && (sectorBefore != NONE))
partitions[i].SetCanBeLogical(0);
else
partitions[i].SetCanBeLogical(lastLogical == 0); // can be logical only if no logicals already
} // if/else
// Now determine if it can be primary. Start by assuming it can be...
partitions[i].SetCanBePrimary(1);
if ((numPrimaries >= 4) && (partitions[i].GetInclusion() != PRIMARY)) {
partitions[i].SetCanBePrimary(0);
if ((partitions[i].GetInclusion() == LOGICAL) && (numLogicals == 1) &&
(numPrimaries == 4))
partitions[i].SetCanBePrimary(1);
} // if
if ((partitions[i].GetStartLBA() > (firstLogical + 1)) &&
(partitions[i].GetLastLBA() < lastLogical))
partitions[i].SetCanBePrimary(0);
} // else if
} // for
} // BasicMBRData::UpdateCanBeLogical()
// Returns the first sector occupied by any logical partition. Note that
// this does NOT include the logical partition's EBR! Returns UINT32_MAX
// if there are no logical partitions defined.
uint64_t BasicMBRData::FirstLogicalLBA(void) {
int i;
uint64_t firstFound = UINT32_MAX;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].GetInclusion() == LOGICAL) &&
(partitions[i].GetStartLBA() < firstFound)) {
firstFound = partitions[i].GetStartLBA();
} // if
} // for
return firstFound;
} // BasicMBRData::FirstLogicalLBA()
// Returns the last sector occupied by any logical partition, or 0 if
// there are no logical partitions defined.
uint64_t BasicMBRData::LastLogicalLBA(void) {
int i;
uint64_t lastFound = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].GetInclusion() == LOGICAL) &&
(partitions[i].GetLastLBA() > lastFound))
lastFound = partitions[i].GetLastLBA();
} // for
return lastFound;
} // BasicMBRData::LastLogicalLBA()
// Returns 1 if logical partitions are contiguous (have no primaries
// in their midst), or 0 if one or more primaries exist between
// logicals.
int BasicMBRData::AreLogicalsContiguous(void) {
int allOK = 1, i = 0;
uint64_t firstLogical, lastLogical;
firstLogical = FirstLogicalLBA() - 1; // subtract 1 for EBR
lastLogical = LastLogicalLBA();
if (lastLogical > 0) {
do {
if ((partitions[i].GetInclusion() == PRIMARY) &&
(partitions[i].GetStartLBA() >= firstLogical) &&
(partitions[i].GetStartLBA() <= lastLogical)) {
allOK = 0;
} // if
i++;
} while ((i < MAX_MBR_PARTS) && allOK);
} // if
return allOK;
} // BasicMBRData::AreLogicalsContiguous()
// Returns 1 if all partitions fit on the disk, given its size; 0 if any
// partition is too big.
int BasicMBRData::DoTheyFit(void) {
int i, allOK = 1;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].GetStartLBA() > diskSize) || (partitions[i].GetLastLBA() > diskSize)) {
allOK = 0;
} // if
} // for
return allOK;
} // BasicMBRData::DoTheyFit(void)
// Returns 1 if there's at least one free sector immediately preceding
// all partitions flagged as logical; 0 if any logical partition lacks
// this space.
int BasicMBRData::SpaceBeforeAllLogicals(void) {
int i = 0, allOK = 1;
do {
if ((partitions[i].GetStartLBA() > 0) && (partitions[i].GetInclusion() == LOGICAL)) {
allOK = allOK && (SectorUsedAs(partitions[i].GetStartLBA() - 1) == EBR);
} // if
i++;
} while (allOK && (i < MAX_MBR_PARTS));
return allOK;
} // BasicMBRData::SpaceBeforeAllLogicals()
// Returns 1 if the partitions describe a legal layout -- all logicals
// are contiguous and have at least one preceding empty sector,
// the number of primaries is under 4 (or under 3 if there are any
// logicals), there are no overlapping partitions, etc.
// Does NOT assume that primaries are numbered 1-4; uses the
// IsItPrimary() function of the MBRPart class to determine
// primary status. Also does NOT consider partition order; there
// can be gaps and it will still be considered legal.
int BasicMBRData::IsLegal(void) {
int allOK;
allOK = (FindOverlaps() == 0);
allOK = (allOK && (NumPrimaries() <= 4));
allOK = (allOK && AreLogicalsContiguous());
allOK = (allOK && DoTheyFit());
allOK = (allOK && SpaceBeforeAllLogicals());
return allOK;
} // BasicMBRData::IsLegal()
// Returns 1 if the 0xEE partition in the protective/hybrid MBR is marked as
// active/bootable.
int BasicMBRData::IsEEActive(void) {
int i, IsActive = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].GetStatus() & 0x80) && (partitions[i].GetType() == 0xEE))
IsActive = 1;
}
return IsActive;
} // BasicMBRData::IsEEActive()
// Finds the next in-use partition, starting with start (will return start
// if it's in use). Returns -1 if no subsequent partition is in use.
int BasicMBRData::FindNextInUse(int start) {
if (start >= MAX_MBR_PARTS)
start = -1;
while ((start < MAX_MBR_PARTS) && (start >= 0) && (partitions[start].GetInclusion() == NONE))
start++;
if ((start < 0) || (start >= MAX_MBR_PARTS))
start = -1;
return start;
} // BasicMBRData::FindFirstLogical();
/*****************************************************
* *
* Functions to create, delete, or change partitions *
* *
*****************************************************/
// Empty all data. Meant mainly for calling by constructors, but it's also
// used by the hybrid MBR functions in the GPTData class.
void BasicMBRData::EmptyMBR(int clearBootloader) {
int i;
// Zero out the boot loader section, the disk signature, and the
// 2-byte nulls area only if requested to do so. (This is the
// default.)
if (clearBootloader == 1) {
EmptyBootloader();
} // if
// Blank out the partitions
for (i = 0; i < MAX_MBR_PARTS; i++) {
partitions[i].Empty();
} // for
MBRSignature = MBR_SIGNATURE;
state = mbr;
} // BasicMBRData::EmptyMBR()
// Blank out the boot loader area. Done with the initial MBR-to-GPT
// conversion, since MBR boot loaders don't understand GPT, and so
// need to be replaced....
void BasicMBRData::EmptyBootloader(void) {
int i;
for (i = 0; i < 440; i++)
code[i] = 0;
nulls = 0;
} // BasicMBRData::EmptyBootloader
// Create a partition of the specified number based on the passed
// partition. This function does *NO* error checking, so it's possible
// to seriously screw up a partition table using this function!
// Note: This function should NOT be used to create the 0xEE partition
// in a conventional GPT configuration, since that partition has
// specific size requirements that this function won't handle. It may
// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
// since those toss the rulebook away anyhow....
void BasicMBRData::AddPart(int num, const MBRPart& newPart) {
partitions[num] = newPart;
} // BasicMBRData::AddPart()
// Create a partition of the specified number, starting LBA, and
// length. This function does almost no error checking, so it's possible
// to seriously screw up a partition table using this function!
// Note: This function should NOT be used to create the 0xEE partition
// in a conventional GPT configuration, since that partition has
// specific size requirements that this function won't handle. It may
// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
// since those toss the rulebook away anyhow....
void BasicMBRData::MakePart(int num, uint64_t start, uint64_t length, int type, int bootable) {
if ((num >= 0) && (num < MAX_MBR_PARTS) && (start <= UINT32_MAX) && (length <= UINT32_MAX)) {
partitions[num].Empty();
partitions[num].SetType(type);
partitions[num].SetLocation(start, length);
if (num < 4)
partitions[num].SetInclusion(PRIMARY);
else
partitions[num].SetInclusion(LOGICAL);
SetPartBootable(num, bootable);
} // if valid partition number & size
} // BasicMBRData::MakePart()
// Set the partition's type code.
// Returns 1 if successful, 0 if not (invalid partition number)
int BasicMBRData::SetPartType(int num, int type) {
int allOK;
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
if (partitions[num].GetLengthLBA() != UINT32_C(0)) {
allOK = partitions[num].SetType(type);
} else allOK = 0;
} else allOK = 0;
return allOK;
} // BasicMBRData::SetPartType()
// Set (or remove) the partition's bootable flag. Setting it is the
// default; pass 0 as bootable to remove the flag.
// Returns 1 if successful, 0 if not (invalid partition number)
int BasicMBRData::SetPartBootable(int num, int bootable) {
int allOK = 1;
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
if (partitions[num].GetLengthLBA() != UINT32_C(0)) {
if (bootable == 0)
partitions[num].SetStatus(UINT8_C(0x00));
else
partitions[num].SetStatus(UINT8_C(0x80));
} else allOK = 0;
} else allOK = 0;
return allOK;
} // BasicMBRData::SetPartBootable()
// Create a partition that fills the most available space. Returns
// 1 if partition was created, 0 otherwise. Intended for use in
// creating hybrid MBRs.
int BasicMBRData::MakeBiggestPart(int i, int type) {
uint64_t start = UINT64_C(1); // starting point for each search
uint64_t firstBlock; // first block in a segment
uint64_t lastBlock; // last block in a segment
uint64_t segmentSize; // size of segment in blocks
uint64_t selectedSegment = UINT64_C(0); // location of largest segment
uint64_t selectedSize = UINT64_C(0); // size of largest segment in blocks
int found = 0;
string anything;
do {
firstBlock = FindFirstAvailable(start);
if (firstBlock > UINT64_C(0)) { // something's free...
lastBlock = FindLastInFree(firstBlock);
segmentSize = lastBlock - firstBlock + UINT64_C(1);
if (segmentSize > selectedSize) {
selectedSize = segmentSize;
selectedSegment = firstBlock;
} // if
start = lastBlock + 1;
} // if
} while (firstBlock != 0);
if ((selectedSize > UINT64_C(0)) && (selectedSize < diskSize)) {
found = 1;
MakePart(i, selectedSegment, selectedSize, type, 0);
} else {
found = 0;
} // if/else
return found;
} // BasicMBRData::MakeBiggestPart(int i)
// Delete partition #i
void BasicMBRData::DeletePartition(int i) {
partitions[i].Empty();
} // BasicMBRData::DeletePartition()
// Set the inclusion status (PRIMARY, LOGICAL, or NONE) with some sanity
// checks to ensure the table remains legal.
// Returns 1 on success, 0 on failure.
int BasicMBRData::SetInclusionwChecks(int num, int inclStatus) {
int allOK = 1, origValue;
if (IsLegal()) {
if ((inclStatus == PRIMARY) || (inclStatus == LOGICAL) || (inclStatus == NONE)) {
origValue = partitions[num].GetInclusion();
partitions[num].SetInclusion(inclStatus);
if (!IsLegal()) {
partitions[num].SetInclusion(origValue);
cerr << "Specified change is not legal! Aborting change!\n";
} // if
} else {
cerr << "Invalid partition inclusion code in BasicMBRData::SetInclusionwChecks()!\n";
} // if/else
} else {
cerr << "Partition table is not currently in a valid state. Aborting change!\n";
allOK = 0;
} // if/else
return allOK;
} // BasicMBRData::SetInclusionwChecks()
// Recomputes the CHS values for the specified partition and adjusts the value.
// Note that this will create a technically incorrect CHS value for EFI GPT (0xEE)
// protective partitions, but this is required by some buggy BIOSes, so I'm
// providing a function to do this deliberately at the user's command.
// This function does nothing if the partition's length is 0.
void BasicMBRData::RecomputeCHS(int partNum) {
partitions[partNum].RecomputeCHS();
} // BasicMBRData::RecomputeCHS()
// Sorts the partitions starting with partition #start. This function
// does NOT pay attention to primary/logical assignment, which is
// critical when writing the partitions.
void BasicMBRData::SortMBR(int start) {
if ((start < MAX_MBR_PARTS) && (start >= 0))
sort(partitions + start, partitions + MAX_MBR_PARTS);
} // BasicMBRData::SortMBR()
// Delete any partitions that are too big to fit on the disk
// or that are too big for MBR (32-bit limits).
// This deletes the partitions by setting values to 0, not just
// by setting them as being omitted.
// Returns the number of partitions deleted in this way.
int BasicMBRData::DeleteOversizedParts() {
int num = 0, i;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].GetStartLBA() > diskSize) || (partitions[i].GetLastLBA() > diskSize) ||
(partitions[i].GetStartLBA() > UINT32_MAX) || (partitions[i].GetLengthLBA() > UINT32_MAX)) {
cerr << "\aWarning: Deleting oversized partition #" << i + 1 << "! Start = "
<< partitions[i].GetStartLBA() << ", length = " << partitions[i].GetLengthLBA() << "\n";
partitions[i].Empty();
num++;
} // if
} // for
return num;
} // BasicMBRData::DeleteOversizedParts()
// Search for and delete extended partitions.
// Returns the number of partitions deleted.
int BasicMBRData::DeleteExtendedParts() {
int i, numDeleted = 0;
uint8_t type;
for (i = 0; i < MAX_MBR_PARTS; i++) {
type = partitions[i].GetType();
if (((type == 0x05) || (type == 0x0f) || (type == (0x85))) &&
(partitions[i].GetLengthLBA() > 0)) {
partitions[i].Empty();
numDeleted++;
} // if
} // for
return numDeleted;
} // BasicMBRData::DeleteExtendedParts()
// Finds any overlapping partitions and omits the smaller of the two.
void BasicMBRData::OmitOverlaps() {
int i, j;
for (i = 0; i < MAX_MBR_PARTS; i++) {
for (j = i + 1; j < MAX_MBR_PARTS; j++) {
if ((partitions[i].GetInclusion() != NONE) &&
partitions[i].DoTheyOverlap(partitions[j])) {
if (partitions[i].GetLengthLBA() < partitions[j].GetLengthLBA())
partitions[i].SetInclusion(NONE);
else
partitions[j].SetInclusion(NONE);
} // if
} // for (j...)
} // for (i...)
} // BasicMBRData::OmitOverlaps()
// Convert as many partitions into logicals as possible, except for
// the first partition, if possible.
void BasicMBRData::MaximizeLogicals() {
int earliestPart = 0, earliestPartWas = NONE, i;
for (i = MAX_MBR_PARTS - 1; i >= 0; i--) {
UpdateCanBeLogical();
earliestPart = i;
if (partitions[i].CanBeLogical()) {
partitions[i].SetInclusion(LOGICAL);
} else if (partitions[i].CanBePrimary()) {
partitions[i].SetInclusion(PRIMARY);
} else {
partitions[i].SetInclusion(NONE);
} // if/elseif/else
} // for
// If we have spare primaries, convert back the earliest partition to
// its original state....
if ((NumPrimaries() < 4) && (partitions[earliestPart].GetInclusion() == LOGICAL))
partitions[earliestPart].SetInclusion(earliestPartWas);
} // BasicMBRData::MaximizeLogicals()
// Add primaries up to the maximum allowed, from the omitted category.
void BasicMBRData::MaximizePrimaries() {
int num, i = 0;
num = NumPrimaries();
while ((num < 4) && (i < MAX_MBR_PARTS)) {
if ((partitions[i].GetInclusion() == NONE) && (partitions[i].CanBePrimary())) {
partitions[i].SetInclusion(PRIMARY);
num++;
UpdateCanBeLogical();
} // if
i++;
} // while
} // BasicMBRData::MaximizePrimaries()
// Remove primary partitions in excess of 4, starting with the later ones,
// in terms of the array location....
void BasicMBRData::TrimPrimaries(void) {
int numToDelete, i = MAX_MBR_PARTS - 1;
numToDelete = NumPrimaries() - 4;
while ((numToDelete > 0) && (i >= 0)) {
if (partitions[i].GetInclusion() == PRIMARY) {
partitions[i].SetInclusion(NONE);
numToDelete--;
} // if
i--;
} // while (numToDelete > 0)
} // BasicMBRData::TrimPrimaries()
// Locates primary partitions located between logical partitions and
// either converts the primaries into logicals (if possible) or omits
// them.
void BasicMBRData::MakeLogicalsContiguous(void) {
uint64_t firstLogicalLBA, lastLogicalLBA;
int i;
firstLogicalLBA = FirstLogicalLBA();
lastLogicalLBA = LastLogicalLBA();
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].GetInclusion() == PRIMARY) &&
(partitions[i].GetStartLBA() >= firstLogicalLBA) &&
(partitions[i].GetLastLBA() <= lastLogicalLBA)) {
if (SectorUsedAs(partitions[i].GetStartLBA() - 1) == NONE)
partitions[i].SetInclusion(LOGICAL);
else
partitions[i].SetInclusion(NONE);
} // if
} // for
} // BasicMBRData::MakeLogicalsContiguous()
// If MBR data aren't legal, adjust primary/logical assignments and,
// if necessary, drop partitions, to make the data legal.
void BasicMBRData::MakeItLegal(void) {
if (!IsLegal()) {
DeleteOversizedParts();
MaximizeLogicals();
MaximizePrimaries();
if (!AreLogicalsContiguous())
MakeLogicalsContiguous();
if (NumPrimaries() > 4)
TrimPrimaries();
OmitOverlaps();
} // if
} // BasicMBRData::MakeItLegal()
// Removes logical partitions and deactivated partitions from first four
// entries (primary space).
// Returns the number of partitions moved.
int BasicMBRData::RemoveLogicalsFromFirstFour(void) {
int i, j, numMoved = 0, swapped = 0;
MBRPart temp;
for (i = 0; i < 4; i++) {
if ((partitions[i].GetInclusion() != PRIMARY) && (partitions[i].GetLengthLBA() > 0)) {
j = 4;
swapped = 0;
do {
if ((partitions[j].GetInclusion() == NONE) && (partitions[j].GetLengthLBA() == 0)) {
temp = partitions[j];
partitions[j] = partitions[i];
partitions[i] = temp;
swapped = 1;
numMoved++;
} // if
j++;
} while ((j < MAX_MBR_PARTS) && !swapped);
if (j >= MAX_MBR_PARTS)
cerr << "Warning! Too many partitions in BasicMBRData::RemoveLogicalsFromFirstFour()!\n";
} // if
} // for i...
return numMoved;
} // BasicMBRData::RemoveLogicalsFromFirstFour()
// Move all primaries into the first four partition spaces
// Returns the number of partitions moved.
int BasicMBRData::MovePrimariesToFirstFour(void) {
int i, j = 0, numMoved = 0, swapped = 0;
MBRPart temp;
for (i = 4; i < MAX_MBR_PARTS; i++) {
if (partitions[i].GetInclusion() == PRIMARY) {
j = 0;
swapped = 0;
do {
if (partitions[j].GetInclusion() != PRIMARY) {
temp = partitions[j];
partitions[j] = partitions[i];
partitions[i] = temp;
swapped = 1;
numMoved++;
} // if
j++;
} while ((j < 4) && !swapped);
} // if
} // for
return numMoved;
} // BasicMBRData::MovePrimariesToFirstFour()
// Create an extended partition, if necessary, to hold the logical partitions.
// This function also sorts the primaries into the first four positions of
// the table.
// Returns 1 on success, 0 on failure.
int BasicMBRData::CreateExtended(void) {
int allOK = 1, i = 0, swapped = 0;
MBRPart temp;
if (IsLegal()) {
// Move logicals out of primary space...
RemoveLogicalsFromFirstFour();
// Move primaries out of logical space...
MovePrimariesToFirstFour();
// Create the extended partition
if (NumLogicals() > 0) {
SortMBR(4); // sort starting from 4 -- that is, logicals only
temp.Empty();
temp.SetStartLBA(FirstLogicalLBA() - 1);
temp.SetLengthLBA(LastLogicalLBA() - FirstLogicalLBA() + 2);
temp.SetType(0x0f, 1);
temp.SetInclusion(PRIMARY);
do {
if ((partitions[i].GetInclusion() == NONE) || (partitions[i].GetLengthLBA() == 0)) {
partitions[i] = temp;
swapped = 1;
} // if
i++;
} while ((i < 4) && !swapped);
if (!swapped) {
cerr << "Could not create extended partition; no room in primary table!\n";
allOK = 0;
} // if
} // if (NumLogicals() > 0)
} else allOK = 0;
// Do a final check for EFI GPT (0xEE) partitions & flag as a problem if found
// along with an extended partition
for (i = 0; i < MAX_MBR_PARTS; i++)
if (swapped && partitions[i].GetType() == 0xEE)
allOK = 0;
return allOK;
} // BasicMBRData::CreateExtended()
/****************************************
* *
* Functions to find data on free space *
* *
****************************************/
// Finds the first free space on the disk from start onward; returns 0
// if none available....
uint64_t BasicMBRData::FindFirstAvailable(uint64_t start) {
uint64_t first;
uint64_t i;
int firstMoved;
if ((start >= (UINT32_MAX - 1)) || (start >= (diskSize - 1)))
return 0;
first = start;
// ...now search through all partitions; if first is within an
// existing partition, move it to the next sector after that
// partition and repeat. If first was moved, set firstMoved
// flag; repeat until firstMoved is not set, so as to catch
// cases where partitions are out of sequential order....
do {
firstMoved = 0;
for (i = 0; i < 4; i++) {
// Check if it's in the existing partition
if ((first >= partitions[i].GetStartLBA()) &&
(first < (partitions[i].GetStartLBA() + partitions[i].GetLengthLBA()))) {
first = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA();
firstMoved = 1;
} // if
} // for
} while (firstMoved == 1);
if ((first >= diskSize) || (first > UINT32_MAX))
first = 0;
return (first);
} // BasicMBRData::FindFirstAvailable()
// Finds the last free sector on the disk from start forward.
uint64_t BasicMBRData::FindLastInFree(uint64_t start) {
uint64_t nearestStart;
uint64_t i;
if ((diskSize <= UINT32_MAX) && (diskSize > 0))
nearestStart = diskSize - 1;
else
nearestStart = UINT32_MAX - 1;
for (i = 0; i < 4; i++) {
if ((nearestStart > partitions[i].GetStartLBA()) &&
(partitions[i].GetStartLBA() > start)) {
nearestStart = partitions[i].GetStartLBA() - 1;
} // if
} // for
return (nearestStart);
} // BasicMBRData::FindLastInFree()
// Finds the first free sector on the disk from start backward.
uint64_t BasicMBRData::FindFirstInFree(uint64_t start) {
uint64_t bestLastLBA, thisLastLBA;
int i;
bestLastLBA = 1;
for (i = 0; i < 4; i++) {
thisLastLBA = partitions[i].GetLastLBA() + 1;
if (thisLastLBA > 0)
thisLastLBA--;
if ((thisLastLBA > bestLastLBA) && (thisLastLBA < start))
bestLastLBA = thisLastLBA + 1;
} // for
return (bestLastLBA);
} // BasicMBRData::FindFirstInFree()
// Returns NONE (unused), PRIMARY, LOGICAL, EBR (for EBR or MBR), or INVALID.
// Note: If the sector immediately before a logical partition is in use by
// another partition, this function returns PRIMARY or LOGICAL for that
// sector, rather than EBR.
int BasicMBRData::SectorUsedAs(uint64_t sector, int topPartNum) {
int i = 0, usedAs = NONE;
do {
if ((partitions[i].GetStartLBA() <= sector) && (partitions[i].GetLastLBA() >= sector))
usedAs = partitions[i].GetInclusion();
if ((partitions[i].GetStartLBA() == (sector + 1)) && (partitions[i].GetInclusion() == LOGICAL))
usedAs = EBR;
if (sector == 0)
usedAs = EBR;
if (sector >= diskSize)
usedAs = INVALID;
i++;
} while ((i < topPartNum) && ((usedAs == NONE) || (usedAs == EBR)));
return usedAs;
} // BasicMBRData::SectorUsedAs()
/******************************************************
* *
* Functions that extract data on specific partitions *
* *
******************************************************/
uint8_t BasicMBRData::GetStatus(int i) {
MBRPart* thePart;
uint8_t retval;
thePart = GetPartition(i);
if (thePart != NULL)
retval = thePart->GetStatus();
else
retval = UINT8_C(0);
return retval;
} // BasicMBRData::GetStatus()
uint8_t BasicMBRData::GetType(int i) {
MBRPart* thePart;
uint8_t retval;
thePart = GetPartition(i);
if (thePart != NULL)
retval = thePart->GetType();
else
retval = UINT8_C(0);
return retval;
} // BasicMBRData::GetType()
uint64_t BasicMBRData::GetFirstSector(int i) {
MBRPart* thePart;
uint64_t retval;
thePart = GetPartition(i);
if (thePart != NULL)
retval = thePart->GetStartLBA();
else
retval = UINT32_C(0);
return retval;
} // BasicMBRData::GetFirstSector()
uint64_t BasicMBRData::GetLength(int i) {
MBRPart* thePart;
uint64_t retval;
thePart = GetPartition(i);
if (thePart != NULL)
retval = thePart->GetLengthLBA();
else
retval = UINT64_C(0);
return retval;
} // BasicMBRData::GetLength()
/***********************
* *
* Protected functions *
* *
***********************/
// Return a pointer to a primary or logical partition, or NULL if
// the partition is out of range....
MBRPart* BasicMBRData::GetPartition(int i) {
MBRPart* thePart = NULL;
if ((i >= 0) && (i < MAX_MBR_PARTS))
thePart = &partitions[i];
return thePart;
} // GetPartition()
/*******************************************
* *
* Functions that involve user interaction *
* *
*******************************************/
// Present the MBR operations menu. Note that the 'w' option does not
// immediately write data; that's handled by the calling function.
// Returns the number of partitions defined on exit, or -1 if the
// user selected the 'q' option. (Thus, the caller should save data
// if the return value is >0, or possibly >=0 depending on intentions.)
int BasicMBRData::DoMenu(const string& prompt) {
int goOn = 1, quitting = 0, retval, num, haveShownInfo = 0;
unsigned int hexCode;
string tempStr;
do {
cout << prompt;
switch (ReadString()[0]) {
case '\0':
goOn = cin.good();
break;
case 'a': case 'A':
num = GetNumber(1, MAX_MBR_PARTS, 1, "Toggle active flag for partition: ") - 1;
if (partitions[num].GetInclusion() != NONE)
partitions[num].SetStatus(partitions[num].GetStatus() ^ 0x80);
break;
case 'c': case 'C':
for (num = 0; num < MAX_MBR_PARTS; num++)
RecomputeCHS(num);
break;
case 'l': case 'L':
num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to set as logical: ") - 1;
SetInclusionwChecks(num, LOGICAL);
break;
case 'o': case 'O':
num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to omit: ") - 1;
SetInclusionwChecks(num, NONE);
break;
case 'p': case 'P':
if (!haveShownInfo) {
cout << "\n** NOTE: Partition numbers do NOT indicate final primary/logical "
<< "status,\n** unlike in most MBR partitioning tools!\n\a";
cout << "\n** Extended partitions are not displayed, but will be generated "
<< "as required.\n";
haveShownInfo = 1;
} // if
DisplayMBRData();
break;
case 'q': case 'Q':
cout << "This will abandon your changes. Are you sure? ";
if (GetYN() == 'Y') {
goOn = 0;
quitting = 1;
} // if
break;
case 'r': case 'R':
num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to set as primary: ") - 1;
SetInclusionwChecks(num, PRIMARY);
break;
case 's': case 'S':
SortMBR();
break;
case 't': case 'T':
num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to change type code: ") - 1;
hexCode = 0x00;
if (partitions[num].GetLengthLBA() > 0) {
while ((hexCode <= 0) || (hexCode > 255)) {
cout << "Enter an MBR hex code: ";
tempStr = ReadString();
if (IsHex(tempStr))
sscanf(tempStr.c_str(), "%x", &hexCode);
} // while
partitions[num].SetType(hexCode);
} // if
break;
case 'w': case 'W':
goOn = 0;
break;
default:
ShowCommands();
break;
} // switch
} while (goOn);
if (quitting)
retval = -1;
else
retval = CountParts();
return (retval);
} // BasicMBRData::DoMenu()
void BasicMBRData::ShowCommands(void) {
cout << "a\ttoggle the active/boot flag\n";
cout << "c\trecompute all CHS values\n";
cout << "l\tset partition as logical\n";
cout << "o\tomit partition\n";
cout << "p\tprint the MBR partition table\n";
cout << "q\tquit without saving changes\n";
cout << "r\tset partition as primary\n";
cout << "s\tsort MBR partitions\n";
cout << "t\tchange partition type code\n";
cout << "w\twrite the MBR partition table to disk and exit\n";
} // BasicMBRData::ShowCommands()
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/openharmony/third_party_gptfdisk.git
git@gitee.com:openharmony/third_party_gptfdisk.git
openharmony
third_party_gptfdisk
third_party_gptfdisk
master

搜索帮助