Misc. updates and bug fixes

This commit is contained in:
srs5694
2010-01-27 23:03:40 -05:00
parent 546a9c7c36
commit fed16d043a
20 changed files with 800 additions and 758 deletions

View File

@@ -1,6 +1,10 @@
0.6.2 (?/??/2010):
------------------
- Fixed bug that caused new protective MBR to not be created when the
MBR was invalid and the GPT was damaged and the user opts to try to
use the GPT data.
- Enabled default partition type code of 0700 when creating partitions
or changing their type codes. (Type 0700, Linux/Windows data, is set if
the user hits the Enter key alone.)

View File

@@ -11,6 +11,7 @@
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <iostream>
#include "attributes.h"
using namespace std;
@@ -25,14 +26,14 @@ Attributes::Attributes(void) {
// appropriate name
for (i = 1; i < NUM_ATR; i++) {
sprintf(temp, "Undefined bit #%d", i);
strcpy(atNames[i], temp);
atNames[i] = temp;
} // for
// Now reset those names that are defined....
strcpy(atNames[0], "system partition");
strcpy(atNames[60], "read-only");
strcpy(atNames[62], "hidden");
strcpy(atNames[63], "do not automount");
atNames[0] = "system partition";
atNames[60] = "read-only";
atNames[62] = "hidden";
atNames[63] = "do not automount";
} // Attributes constructor
// Destructor.
@@ -43,16 +44,18 @@ Attributes::~Attributes(void) {
void Attributes::DisplayAttributes(void) {
int i;
printf("Attribute value is %llX. Set fields are:\n",
(unsigned long long) attributes);
cout << "Attribute value is ";
cout.setf(ios::uppercase);
cout.fill('0');
cout.width(16);
cout << hex << attributes << dec << ". Set fields are:\n";
for (i = 0; i < NUM_ATR; i++) {
if (((attributes >> i) % 2) == 1) { // bit is set
/* if (strncmp("Undefined", atNames[i], 9) != 0)
printf("%s\n", atNames[i]); */
if (strncmp("Undefined", atNames[NUM_ATR - i - 1], 9) != 0)
printf("%s\n", atNames[NUM_ATR - i - 1]);
if (atNames[NUM_ATR - i - 1].substr(0, 9) != "Undefined")
cout << atNames[NUM_ATR - i - 1] << "\n";
} // if
} // for
cout.fill(' ');
} // Attributes::DisplayAttributes()
// Prompt user for attribute changes
@@ -60,23 +63,22 @@ void Attributes::ChangeAttributes(void) {
int response, i;
uint64_t bitValue;
printf("Known attributes are:\n");
cout << "Known attributes are:\n";
for (i = 0; i < NUM_ATR; i++) {
if (strncmp("Undefined", atNames[i], 9) != 0)
printf("%d - %s\n", i, atNames[i]);
if (atNames[i].substr(0, 9) != "Undefined")
cout << i << " - " << atNames[i] << "\n";
} // for
do {
response = GetNumber(0, 64, -1, "Toggle which attribute field (0-63, 64 to exit): ");
response = GetNumber(0, 64, -1, (string) "Toggle which attribute field (0-63, 64 to exit): ");
if (response != 64) {
bitValue = PowerOf2(NUM_ATR - response - 1); // Find the integer value of the bit
// bitValue = PowerOf2(response); // Find the integer value of the bit
if ((bitValue & attributes) == bitValue) { // bit is set
attributes -= bitValue; // so unset it
printf("Have disabled the '%s' attribute.\n", atNames[response]);
cout << "Have disabled the '" << atNames[response] << "' attribute.\n";
} else { // bit is not set
attributes += bitValue; // so set it
printf("Have enabled the '%s' attribute.\n", atNames[response]);
cout << "Have enabled the '" << atNames[response] << "' attribute.\n";
} // if/else
} // if
} while (response != 64);

View File

@@ -18,7 +18,7 @@ using namespace std;
class Attributes {
protected:
uint64_t attributes;
char atNames[NUM_ATR][ATR_NAME_SIZE];
string atNames[NUM_ATR];
public:
Attributes(void);
~Attributes(void);

115
bsd.cc
View File

@@ -14,9 +14,10 @@
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
#include <iostream>
#include <string>
#include "support.h"
#include "bsd.h"
@@ -41,39 +42,30 @@ BSDData::~BSDData(void) {
// Read BSD disklabel data from the specified device filename. This function
// just opens the device file and then calls an overloaded function to do
// the bulk of the work.
int BSDData::ReadBSDData(char* device, uint64_t startSector, uint64_t endSector) {
int allOK = 1, tempMyDisk = 0;
// the bulk of the work. Returns 1 on success, 0 on failure.
int BSDData::ReadBSDData(string *device, uint64_t startSector, uint64_t endSector) {
int allOK = 1;
DiskIO myDisk;
if (device != NULL) {
if (myDisk == NULL) {
myDisk = new DiskIO;
tempMyDisk = 1;
} // if
if (myDisk->OpenForRead(device)) {
ReadBSDData(myDisk, startSector, endSector);
if (*device != "") {
if (myDisk.OpenForRead(*device)) {
allOK = ReadBSDData(&myDisk, startSector, endSector);
} else {
allOK = 0;
} // if/else
myDisk->Close();
myDisk.Close();
} else {
allOK = 0;
} // if/else
if (tempMyDisk) {
delete myDisk;
myDisk = NULL;
} // if
return allOK;
} // BSDData::ReadBSDData() (device filename version)
// Load the BSD disklabel data from an already-opened disk
// file, starting with the specified sector number.
void BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSector) {
int BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSector) {
uint8_t buffer[4096]; // I/O buffer
int i, err, foundSig = 0, bigEnd = 0;
int i, err, foundSig = 0, bigEnd = 0, allOK = 1;
int relative = 0; // assume absolute partition sector numbering
uint32_t realSig;
uint32_t* temp32;
@@ -81,54 +73,59 @@ void BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSec
BSDRecord* tempRecords;
int offset[NUM_OFFSETS] = { LABEL_OFFSET1, LABEL_OFFSET2 };
myDisk = theDisk;
// myDisk = theDisk;
labelFirstLBA = startSector;
labelLastLBA = endSector;
offset[1] = myDisk->GetBlockSize();
offset[1] = theDisk->GetBlockSize();
// Read 4096 bytes (eight 512-byte sectors or equivalent)
// into memory; we'll extract data from this buffer.
// (Done to work around FreeBSD limitation on size of reads
// from block devices.)
myDisk->Seek(startSector /* * myDisk->GetBlockSize() */);
myDisk->Read(buffer, 4096);
allOK = theDisk->Seek(startSector);
if (allOK) allOK = theDisk->Read(buffer, 4096);
// Do some strangeness to support big-endian architectures...
bigEnd = (IsLittleEndian() == 0);
realSig = BSD_SIGNATURE;
if (bigEnd)
if (bigEnd && allOK)
ReverseBytes(&realSig, 4);
// Look for the signature at any of two locations.
// Note that the signature is repeated at both the original
// offset and 132 bytes later, so we need two checks....
i = 0;
do {
temp32 = (uint32_t*) &buffer[offset[i]];
signature = *temp32;
if (signature == realSig) { // found first, look for second
temp32 = (uint32_t*) &buffer[offset[i] + 132];
signature2 = *temp32;
if (signature2 == realSig) {
foundSig = 1;
labelStart = offset[i];
} // if found signature
} // if/else
i++;
} while ((!foundSig) && (i < NUM_OFFSETS));
if (allOK) {
i = 0;
do {
temp32 = (uint32_t*) &buffer[offset[i]];
signature = *temp32;
if (signature == realSig) { // found first, look for second
temp32 = (uint32_t*) &buffer[offset[i] + 132];
signature2 = *temp32;
if (signature2 == realSig) {
foundSig = 1;
labelStart = offset[i];
} // if found signature
} // if/else
i++;
} while ((!foundSig) && (i < NUM_OFFSETS));
allOK = foundSig;
} // if
// Load partition metadata from the buffer....
temp32 = (uint32_t*) &buffer[labelStart + 40];
sectorSize = *temp32;
temp16 = (uint16_t*) &buffer[labelStart + 138];
numParts = *temp16;
if (allOK) {
temp32 = (uint32_t*) &buffer[labelStart + 40];
sectorSize = *temp32;
temp16 = (uint16_t*) &buffer[labelStart + 138];
numParts = *temp16;
} // if
// Make it big-endian-aware....
if (IsLittleEndian() == 0)
if ((IsLittleEndian() == 0) && allOK)
ReverseMetaBytes();
// Check validity of the data and flag it appropriately....
if (foundSig && (numParts <= MAX_BSD_PARTS)) {
if (foundSig && (numParts <= MAX_BSD_PARTS) && allOK) {
state = bsd;
} else {
state = bsd_invalid;
@@ -167,7 +164,8 @@ void BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSec
} // if
} // if signatures OK
// DisplayBSDData();
} // BSDData::ReadBSDData(int fd, uint64_t startSector)
return allOK;
} // BSDData::ReadBSDData(DiskIO* theDisk, uint64_t startSector)
// Reverse metadata's byte order; called only on big-endian systems
void BSDData::ReverseMetaBytes(void) {
@@ -182,12 +180,19 @@ void BSDData::DisplayBSDData(void) {
int i;
if (state == bsd) {
printf("BSD partitions:\n");
printf("Number\t Start (sector)\t Length (sectors)\tType\n");
cout << "BSD partitions:\n";
for (i = 0; i < numParts; i++) {
printf("%4d\t%13lu\t%15lu \t0x%02X\n", i + 1,
(unsigned long) partitions[i].firstLBA,
(unsigned long) partitions[i].lengthLBA, partitions[i].fsType);
cout.width(4);
cout << i + 1 << "\t";
cout.width(13);
cout << partitions[i].firstLBA << "\t";
cout.width(15);
cout << partitions[i].lengthLBA << " \t0x";
cout.width(2);
cout.fill('0');
cout.setf(ios::uppercase);
cout << hex << (int) partitions[i].fsType << "\n" << dec;
cout.fill(' ');
} // for
} // if
} // BSDData::DisplayBSDData()
@@ -199,14 +204,14 @@ int BSDData::ShowState(void) {
switch (state) {
case bsd_invalid:
printf(" BSD: not present\n");
cout << " BSD: not present\n";
break;
case bsd:
printf(" BSD: present\n");
cout << " BSD: present\n";
retval = 1;
break;
default:
printf("\a BSD: unknown -- bug!\n");
cout << "\a BSD: unknown -- bug!\n";
break;
} // switch
return retval;
@@ -318,7 +323,7 @@ GPTPart BSDData::AsGPT(int i) {
guid.SetType(0x0700); break;
} // switch
// Set the partition name to the name of the type code....
guid.SetName((unsigned char*) guid.GetNameType().c_str());
guid.SetName(guid.GetNameType());
} // if
return guid;
} // BSDData::AsGPT()

5
bsd.h
View File

@@ -69,12 +69,11 @@ class BSDData {
uint64_t labelLastLBA; // final sector of BSD disklabel
uint64_t labelStart; // BSD disklabel start point in bytes from labelFirstLBA
BSDValidity state;
DiskIO *myDisk;
public:
BSDData(void);
~BSDData(void);
int ReadBSDData(char* deviceFilename, uint64_t startSector, uint64_t endSector);
void ReadBSDData(DiskIO *myDisk, uint64_t startSector, uint64_t endSector);
int ReadBSDData(string *deviceFilename, uint64_t startSector, uint64_t endSector);
int ReadBSDData(DiskIO *myDisk, uint64_t startSector, uint64_t endSector);
void ReverseMetaBytes(void);
void DisplayBSDData(void);
int ShowState(void); // returns 1 if BSD disklabel detected

View File

@@ -16,7 +16,7 @@
#define __STDC_CONSTANT_MACROS
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <stdint.h>
#include <errno.h>
@@ -24,7 +24,6 @@
#include <sys/stat.h>
#include <iostream>
#include "support.h"
#include "diskio.h"
using namespace std;
@@ -50,10 +49,9 @@ int DiskIO::OpenForRead(void) {
if (shouldOpen) {
fd = open(realFilename.c_str(), O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Problem opening %s for reading! Error is %d\n",
realFilename.c_str(), errno);
cerr << "Problem opening " << realFilename << " for reading! Error is " << errno << "\n";
if (errno == EACCES) { // User is probably not running as root
fprintf(stderr, "You must run this program as root or use sudo!\n");
cerr << "You must run this program as root or use sudo!\n";
} // if
realFilename = "";
userFilename = "";
@@ -82,7 +80,7 @@ int DiskIO::OpenForWrite(void) {
#ifdef __APPLE__
// MacOS X requires a shared lock under some circumstances....
if (fd < 0) {
fd = open(realFilename.c_str(), O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH | O_SHLOCK);
fd = open(realFilename.c_str(), O_WRONLY | O_SHLOCK);
} // if
#endif
if (fd >= 0) {
@@ -133,8 +131,8 @@ int DiskIO::GetBlockSize(void) {
// 32-bit code returns EINVAL, I don't know why. I know I'm treading on
// thin ice here, but it should be OK in all but very weird cases....
if ((errno != ENOTTY) && (errno != EINVAL)) {
printf("\aError %d when determining sector size! Setting sector size to %d\n",
errno, SECTOR_SIZE);
cerr << "\aError " << errno << " when determining sector size! Setting sector size to "
<< SECTOR_SIZE << "\n";
} // if
} // if (err == -1)
} // if (isOpen)
@@ -155,8 +153,8 @@ void DiskIO::DiskSync(void) {
if (isOpen) {
sync();
#ifdef __APPLE__
printf("Warning: The kernel may continue to use old or deleted partitions.\n"
"You should reboot or remove the drive.\n");
cout << "Warning: The kernel may continue to use old or deleted partitions.\n"
<< "You should reboot or remove the drive.\n";
/* don't know if this helps
* it definitely will get things on disk though:
* http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
@@ -166,22 +164,22 @@ void DiskIO::DiskSync(void) {
#ifdef __FreeBSD__
sleep(2);
i = ioctl(fd, DIOCGFLUSH);
printf("Warning: The kernel may continue to use old or deleted partitions.\n"
"You should reboot or remove the drive.\n");
cout << "Warning: The kernel may continue to use old or deleted partitions.\n"
<< "You should reboot or remove the drive.\n";
platformFound++;
#endif
#ifdef __linux__
sleep(2);
i = ioctl(fd, BLKRRPART);
if (i)
printf("Warning: The kernel is still using the old partition table.\n"
"The new table will be used at the next reboot.\n");
cout << "Warning: The kernel is still using the old partition table.\n"
<< "The new table will be used at the next reboot.\n";
platformFound++;
#endif
if (platformFound == 0)
fprintf(stderr, "Warning: Platform not recognized!\n");
cerr << "Warning: Platform not recognized!\n";
if (platformFound > 1)
fprintf(stderr, "\nWarning: We seem to be running on multiple platforms!\n");
cerr << "\nWarning: We seem to be running on multiple platforms!\n";
} // if (isOpen)
} // DiskIO::DiskSync()
@@ -233,9 +231,6 @@ int DiskIO::Read(void* buffer, int numBytes) {
// Read the data into temporary space, then copy it to buffer
retval = read(fd, tempSpace, numBlocks * blockSize);
memcpy(buffer, tempSpace, numBytes);
/* for (i = 0; i < numBytes; i++) {
((char*) buffer)[i] = tempSpace[i];
} // for */
// Adjust the return value, if necessary....
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
@@ -347,7 +342,7 @@ uint64_t DiskIO::DiskSize(int *err) {
platformFound++;
#endif
if (platformFound != 1)
fprintf(stderr, "Warning! We seem to be running on no known platform!\n");
cerr << "Warning! We seem to be running on no known platform!\n";
// The above methods have failed, so let's assume it's a regular
// file (a QEMU image, dd backup, or what have you) and see what
@@ -356,8 +351,8 @@ uint64_t DiskIO::DiskSize(int *err) {
if (fstat64(fd, &st) == 0) {
bytes = (off_t) st.st_size;
if ((bytes % UINT64_C(512)) != 0)
fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
" Misbehavior is likely!\n\a");
cerr << "Warning: File size is not a multiple of 512 bytes!"
<< " Misbehavior is likely!\n\a";
sectors = bytes / UINT64_C(512);
} // if
} // if

View File

@@ -114,11 +114,11 @@ int DiskIO::FindAlignment(void) {
int err = -2, errnum = 0, result = 8, physicalSectorSize = 4096;
uint64_t diskSize;
printf("Entering FindAlignment()\n");
cout << "Entering FindAlignment()\n";
#if defined (__linux__) && defined (BLKPBSZGET)
err = ioctl(fd, BLKPBSZGET, &physicalSectorSize);
printf("In FindAlignment(), physicalSectorSize = %d, err = %d\n", physicalSectorSize, err);
// printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize);
cout << "In FindAlignment(), physicalSectorSize = " << physicalSectorSize
<< ", err = " << err << "\n";
#else
err = -1;
#endif

View File

@@ -59,10 +59,8 @@ class DiskIO {
#endif
public:
DiskIO(void);
// DiskIO(const DiskIO & orig);
~DiskIO(void);
// DiskIO & operator=(const DiskIO & orig);
void MakeRealName(void);
int OpenForRead(string filename);
int OpenForRead(void);

185
gdisk.cc
View File

@@ -9,18 +9,20 @@
//#include <iostream>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <string.h>
#include <string>
#include <iostream>
#include "mbr.h"
#include "gpt.h"
#include "support.h"
// Function prototypes....
void MainMenu(char* filename, struct GPTData* theGPT);
void MainMenu(string filename, struct GPTData* theGPT);
void ShowCommands(void);
void ExpertsMenu(char* filename, struct GPTData* theGPT);
void ExpertsMenu(string filename, struct GPTData* theGPT);
void ShowExpertCommands(void);
void RecoveryMenu(char* filename, struct GPTData* theGPT);
void RecoveryMenu(string filename, struct GPTData* theGPT);
void ShowRecoveryCommands(void);
int main(int argc, char* argv[]) {
@@ -28,7 +30,7 @@ int main(int argc, char* argv[]) {
int doMore = 1;
char* device = NULL;
printf("GPT fdisk (gdisk) version %s\n\n", GPTFDISK_VERSION);
cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n";
if (argc == 2) { // basic usage
if (SizesOK()) {
@@ -44,22 +46,22 @@ int main(int argc, char* argv[]) {
} else if (strcmp(argv[2], "-l") == 0) {
device = argv[1];
} else { // 3 arguments, but none is "-l"
fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
cerr << "Usage: " << argv[0] << " [-l] device_file\n";
} // if/elseif/else
if (device != NULL) {
theGPT.JustLooking();
doMore = theGPT.LoadPartitions(device);
doMore = theGPT.LoadPartitions((string) device);
if (doMore) theGPT.DisplayGPTData();
} // if
} // if
} else {
fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
cerr << "Usage: " << argv[0] << " [-l] device_file\n";
} // if/else
} // main
// Accept a command and execute it. Returns only when the user
// wants to exit (such as after a 'w' or 'q' command).
void MainMenu(char* filename, struct GPTData* theGPT) {
void MainMenu(string filename, struct GPTData* theGPT) {
char command, line[255], buFile[255];
char* junk;
int goOn = 1;
@@ -67,12 +69,14 @@ void MainMenu(char* filename, struct GPTData* theGPT) {
uint32_t temp1, temp2;
do {
printf("\nCommand (? for help): ");
cout << "\nCommand (? for help): ";
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
case '\n':
break;
case 'b': case 'B':
printf("Enter backup filename to save: ");
cout << "Enter backup filename to save: ";
junk = fgets(line, 255, stdin);
sscanf(line, "%s", (char*) &buFile);
theGPT->SaveGPTBackup(buFile);
@@ -81,7 +85,7 @@ void MainMenu(char* filename, struct GPTData* theGPT) {
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
theGPT->SetName(theGPT->GetPartNum());
else
printf("No partitions\n");
cout << "No partitions\n";
break;
case 'd': case 'D':
theGPT->DeletePartition();
@@ -96,8 +100,8 @@ void MainMenu(char* filename, struct GPTData* theGPT) {
theGPT->CreatePartition();
break;
case 'o': case 'O':
printf("This option deletes all partitions and creates a new "
"protective MBR.\nProceed? ");
cout << "This option deletes all partitions and creates a new protective MBR.\n"
<< "Proceed? ";
if (GetYN() == 'Y') {
theGPT->ClearGPTData();
theGPT->MakeProtectiveMBR();
@@ -115,7 +119,7 @@ void MainMenu(char* filename, struct GPTData* theGPT) {
break;
case 's': case 'S':
theGPT->SortGPT();
printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
cout << "You may need to edit /etc/fstab and/or your boot loader configuration!\n";
break;
case 't': case 'T':
theGPT->ChangePartType();
@@ -139,27 +143,27 @@ void MainMenu(char* filename, struct GPTData* theGPT) {
} // MainMenu()
void ShowCommands(void) {
printf("b\tback up GPT data to a file\n");
printf("c\tchange a partition's name\n");
printf("d\tdelete a partition\n");
printf("i\tshow detailed information on a partition\n");
printf("l\tlist known partition types\n");
printf("n\tadd a new partition\n");
printf("o\tcreate a new empty GUID partition table (GPT)\n");
printf("p\tprint the partition table\n");
printf("q\tquit without saving changes\n");
printf("r\trecovery and transformation options (experts only)\n");
printf("s\tsort partitions\n");
printf("t\tchange a partition's type code\n");
printf("v\tverify disk\n");
printf("w\twrite table to disk and exit\n");
printf("x\textra functionality (experts only)\n");
printf("?\tprint this menu\n");
cout << "b\tback up GPT data to a file\n";
cout << "c\tchange a partition's name\n";
cout << "d\tdelete a partition\n";
cout << "i\tshow detailed information on a partition\n";
cout << "l\tlist known partition types\n";
cout << "n\tadd a new partition\n";
cout << "o\tcreate a new empty GUID partition table (GPT)\n";
cout << "p\tprint the partition table\n";
cout << "q\tquit without saving changes\n";
cout << "r\trecovery and transformation options (experts only)\n";
cout << "s\tsort partitions\n";
cout << "t\tchange a partition's type code\n";
cout << "v\tverify disk\n";
cout << "w\twrite table to disk and exit\n";
cout << "x\textra functionality (experts only)\n";
cout << "?\tprint this menu\n";
} // ShowCommands()
// Accept a recovery & transformation menu command. Returns only when the user
// issues an exit command, such as 'w' or 'q'.
void RecoveryMenu(char* filename, struct GPTData* theGPT) {
void RecoveryMenu(string filename, struct GPTData* theGPT) {
char command, line[255], buFile[255];
char* junk;
PartTypes typeHelper;
@@ -167,16 +171,18 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
int goOn = 1;
do {
printf("\nRecovery/transformation command (? for help): ");
cout << "\nRecovery/transformation command (? for help): ";
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
case '\n':
break;
case 'b': case 'B':
theGPT->RebuildMainHeader();
break;
case 'c': case 'C':
printf("Warning! This will probably do weird things if you've converted an MBR to\n"
"GPT form and haven't yet saved the GPT! Proceed? ");
cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
<< "GPT form and haven't yet saved the GPT! Proceed? ";
if (GetYN() == 'Y')
theGPT->LoadSecondTableAsMain();
break;
@@ -184,18 +190,18 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
theGPT->RebuildSecondHeader();
break;
case 'e': case 'E':
printf("Warning! This will probably do weird things if you've converted an MBR to\n"
"GPT form and haven't yet saved the GPT! Proceed? ");
cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
<< "GPT form and haven't yet saved the GPT! Proceed? ";
if (GetYN() == 'Y')
theGPT->LoadMainTable();
break;
case 'f': case 'F':
printf("Warning! This will destroy the currently defined partitions! Proceed? ");
cout << "Warning! This will destroy the currently defined partitions! Proceed? ";
if (GetYN() == 'Y') {
if (theGPT->LoadMBR(filename) == 1) { // successful load
theGPT->XFormPartitions();
} else {
printf("Problem loading MBR! GPT is untouched; regenerating protective MBR!\n");
cout << "Problem loading MBR! GPT is untouched; regenerating protective MBR!\n";
theGPT->MakeProtectiveMBR();
} // if/else
} // if
@@ -203,13 +209,13 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
case 'g': case 'G':
temp1 = theGPT->XFormToMBR();
if (temp1 > 0) {
printf("Converted %d partitions. Finalize and exit? ", temp1);
cout << "Converted " << temp1 << " partitions. Finalize and exit? ";
if (GetYN() == 'Y') {
if (theGPT->DestroyGPT(0) > 0)
goOn = 0;
} else {
theGPT->MakeProtectiveMBR();
printf("Note: New protective MBR created.\n");
cout << "Note: New protective MBR created.\n";
} // if/else
} // if
break;
@@ -220,7 +226,7 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
theGPT->ShowDetails();
break;
case 'l': case 'L':
printf("Enter backup filename to load: ");
cout << "Enter backup filename to load: ";
junk = fgets(line, 255, stdin);
sscanf(line, "%s", (char*) &buFile);
theGPT->LoadGPTBackup(buFile);
@@ -261,29 +267,29 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
} // RecoveryMenu()
void ShowRecoveryCommands(void) {
printf("b\tuse backup GPT header (rebuilding main)\n");
printf("c\tload backup partition table from disk (rebuilding main)\n");
printf("d\tuse main GPT header (rebuilding backup)\n");
printf("e\tload main partition table from disk (rebuilding backup)\n");
printf("f\tload MBR and build fresh GPT from it\n");
printf("g\tconvert GPT into MBR and exit\n");
printf("h\tmake hybrid MBR\n");
printf("i\tshow detailed information on a partition\n");
printf("l\tload partition data from a backup file\n");
printf("m\treturn to main menu\n");
printf("o\tprint protective MBR data\n");
printf("p\tprint the partition table\n");
printf("q\tquit without saving changes\n");
printf("t\ttransform BSD disklabel partition\n");
printf("v\tverify disk\n");
printf("w\twrite table to disk and exit\n");
printf("x\textra functionality (experts only)\n");
printf("?\tprint this menu\n");
cout << "b\tuse backup GPT header (rebuilding main)\n";
cout << "c\tload backup partition table from disk (rebuilding main)\n";
cout << "d\tuse main GPT header (rebuilding backup)\n";
cout << "e\tload main partition table from disk (rebuilding backup)\n";
cout << "f\tload MBR and build fresh GPT from it\n";
cout << "g\tconvert GPT into MBR and exit\n";
cout << "h\tmake hybrid MBR\n";
cout << "i\tshow detailed information on a partition\n";
cout << "l\tload partition data from a backup file\n";
cout << "m\treturn to main menu\n";
cout << "o\tprint protective MBR data\n";
cout << "p\tprint the partition table\n";
cout << "q\tquit without saving changes\n";
cout << "t\ttransform BSD disklabel partition\n";
cout << "v\tverify disk\n";
cout << "w\twrite table to disk and exit\n";
cout << "x\textra functionality (experts only)\n";
cout << "?\tprint this menu\n";
} // ShowRecoveryCommands()
// Accept an experts' menu command. Returns only after the user
// selects an exit command, such as 'w' or 'q'.
void ExpertsMenu(char* filename, struct GPTData* theGPT) {
void ExpertsMenu(string filename, struct GPTData* theGPT) {
char command, line[255];
char* junk;
PartTypes typeHelper;
@@ -292,40 +298,43 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
int goOn = 1;
do {
printf("\nExpert command (? for help): ");
cout << "\nExpert command (? for help): ";
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
case '\n':
break;
case 'a': case 'A':
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
theGPT->SetAttributes(theGPT->GetPartNum());
else
printf("No partitions\n");
cout << "No partitions\n";
break;
case 'c': case 'C':
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
pn = theGPT->GetPartNum();
printf("Enter the partition's new unique GUID:\n");
cout << "Enter the partition's new unique GUID:\n";
theGPT->SetPartitionGUID(pn, GetGUID());
} else printf("No partitions\n");
} else cout << "No partitions\n";
break;
case 'd': case 'D':
printf("Partitions will begin on %d-sector boundaries.\n",
theGPT->GetAlignment());
cout << "Partitions will begin on " << theGPT->GetAlignment()
<< "-sector boundaries.\n";
break;
case 'e': case 'E':
printf("Relocating backup data structures to the end of the disk\n");
cout << "Relocating backup data structures to the end of the disk\n";
theGPT->MoveSecondHeaderToEnd();
break;
case 'g': case 'G':
printf("Enter the disk's unique GUID:\n");
cout << "Enter the disk's unique GUID:\n";
theGPT->SetDiskGUID(GetGUID());
break;
case 'i': case 'I':
theGPT->ShowDetails();
break;
case 'l': case 'L':
temp1 = GetNumber(1, 128, 8, "Enter the sector alignment value (1-128, default = 8): ");
temp1 = GetNumber(1, 128, 8, (string)
"Enter the sector alignment value (1-128, default = 8): ");
theGPT->SetAlignment(temp1);
break;
case 'm': case 'M':
@@ -372,22 +381,22 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
} // ExpertsMenu()
void ShowExpertCommands(void) {
printf("a\tset attributes\n");
printf("c\tchange partition GUID\n");
printf("d\tdisplay the sector alignment value\n");
printf("e\trelocate backup data structures to the end of the disk\n");
printf("g\tchange disk GUID\n");
printf("i\tshow detailed information on a partition\n");
printf("l\tset the sector alignment value\n");
printf("m\treturn to main menu\n");
printf("n\tcreate a new protective MBR\n");
printf("o\tprint protective MBR data\n");
printf("p\tprint the partition table\n");
printf("q\tquit without saving changes\n");
printf("r\trecovery and transformation options (experts only)\n");
printf("s\tresize partition table\n");
printf("v\tverify disk\n");
printf("w\twrite table to disk and exit\n");
printf("z\tzap (destroy) GPT data structures and exit\n");
printf("?\tprint this menu\n");
cout << "a\tset attributes\n";
cout << "c\tchange partition GUID\n";
cout << "d\tdisplay the sector alignment value\n";
cout << "e\trelocate backup data structures to the end of the disk\n";
cout << "g\tchange disk GUID\n";
cout << "i\tshow detailed information on a partition\n";
cout << "l\tset the sector alignment value\n";
cout << "m\treturn to main menu\n";
cout << "n\tcreate a new protective MBR\n";
cout << "o\tprint protective MBR data\n";
cout << "p\tprint the partition table\n";
cout << "q\tquit without saving changes\n";
cout << "r\trecovery and transformation options (experts only)\n";
cout << "s\tresize partition table\n";
cout << "v\tverify disk\n";
cout << "w\twrite table to disk and exit\n";
cout << "z\tzap (destroy) GPT data structures and exit\n";
cout << "?\tprint this menu\n";
} // ShowExpertCommands()

701
gpt.cc

File diff suppressed because it is too large Load Diff

16
gpt.h
View File

@@ -16,7 +16,7 @@
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
#define GPTFDISK_VERSION "0.6.2-pre1"
#define GPTFDISK_VERSION "0.6.2-pre2"
using namespace std;
@@ -59,7 +59,7 @@ protected:
GPTPart *partitions;
struct GPTHeader secondHeader;
MBRData protectiveMBR;
char device[256]; // device filename
string device; // device filename
DiskIO myDisk;
uint32_t blockSize; // device block size
uint64_t diskSize; // size of device, in blocks
@@ -78,7 +78,7 @@ protected:
public:
// Basic necessary functions....
GPTData(void);
GPTData(char* deviceFilename);
GPTData(string deviceFilename);
~GPTData(void);
// Verify (or update) data integrity
@@ -93,15 +93,15 @@ public:
int FindOverlaps(void);
// Load or save data from/to disk
int LoadMBR(char* f) {return protectiveMBR.ReadMBRData(f);}
int LoadMBR(string f) {return protectiveMBR.ReadMBRData(f);}
void PartitionScan(void);
int LoadPartitions(char* deviceFilename);
int LoadPartitions(string deviceFilename);
int ForceLoadGPTData(void);
int LoadMainTable(void);
int LoadSecondTableAsMain(void);
int SaveGPTData(int quiet = 0);
int SaveGPTBackup(char* filename);
int LoadGPTBackup(char* filename);
int SaveGPTBackup(string filename);
int LoadGPTBackup(string filename);
// Display data....
void ShowAPMState(void);
@@ -137,7 +137,7 @@ public:
void SortGPT(void);
int ClearGPTData(void);
void MoveSecondHeaderToEnd();
int SetName(uint32_t partNum, char* theName = NULL);
int SetName(uint32_t partNum, string theName = "");
void SetDiskGUID(GUIDData newGUID);
int SetPartitionGUID(uint32_t pn, GUIDData theGUID);
int ChangePartType(uint32_t pn, uint16_t hexCode);

View File

@@ -15,8 +15,9 @@
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#include <stdio.h>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include "gptpart.h"
#include "attributes.h"
@@ -34,14 +35,14 @@ GPTPart::GPTPart(void) {
GPTPart::~GPTPart(void) {
} // destructor
// Return partition's name field
// Return partition's name field, converted to a C++ ASCII string
string GPTPart::GetName(void) {
string theName;
int i;
/* if (ref == NULL)
ref = (unsigned char*) malloc(NAME_SIZE * sizeof (unsigned char));
strcpy((char*) ref, (char*) name); */
theName = (const char*) name;
for (i = 0; i < NAME_SIZE; i += 2) {
theName += name[i];
} // for
return theName;
} // GPTPart::GetName()
@@ -53,12 +54,7 @@ uint16_t GPTPart::GetHexType(void) {
// Return a plain-text description of the partition type (e.g., "Linux/Windows
// data" or "Linux swap").
string GPTPart::GetNameType(void) {
string temp;
char theName[255];
temp = typeHelper.GUIDToName(partitionType, theName);
return temp;
return typeHelper.GUIDToName(partitionType);
} // GPTPart::GetNameType()
// Compute and return the partition's length (or 0 if the end is incorrectly
@@ -141,50 +137,56 @@ void GPTPart::ReversePartBytes(void) {
// Display summary information; does nothing if the partition is empty.
void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
char sizeInSI[255];
int j = 0;
string sizeInSI;
int i;
if (firstLBA != 0) {
BytesToSI(blockSize * (lastLBA - firstLBA + 1), sizeInSI);
printf("%4d %14lu %14lu", partNum + 1, (unsigned long) firstLBA,
(unsigned long) lastLBA);
printf(" %-10s %04X ", sizeInSI,
typeHelper.GUIDToID(partitionType));
while ((name[j] != '\0') && (j < 44)) {
printf("%c", name[j]);
j += 2;
} // while
printf("\n");
sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1));
cout.width(4);
cout << partNum + 1 << " ";
cout.width(14);
cout << firstLBA << " ";
cout.width(14);
cout << lastLBA << " ";
cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
for (i = 0; i < 9 - sizeInSI.length(); i++) cout << " ";
cout.fill('0');
cout.width(4);
cout.setf(ios::uppercase);
cout << hex << typeHelper.GUIDToID(partitionType) << " " << dec;
cout.fill(' ');
cout.setf(ios::right);
cout << GetName().substr(0, 23) << "\n";
cout.fill(' ');
} // if
} // GPTPart::ShowSummary()
// Show detailed partition information. Does nothing if the partition is
// empty (as determined by firstLBA being 0).
void GPTPart::ShowDetails(uint32_t blockSize) {
char temp[255];
int i;
uint64_t size;
if (firstLBA != 0) {
printf("Partition GUID code: %s ", GUIDToStr(partitionType, temp));
printf("(%s)\n", typeHelper.GUIDToName(partitionType, temp));
printf("Partition unique GUID: %s\n", GUIDToStr(uniqueGUID, temp));
cout << "Partition GUID code: " << GUIDToStr(partitionType);
cout << " (" << typeHelper.GUIDToName(partitionType) << ")\n";
cout << "Partition unique GUID: " << GUIDToStr(uniqueGUID) << "\n";
printf("First sector: %llu ", firstLBA);
printf("(at %s)\n", BytesToSI(firstLBA * blockSize, temp));
printf("Last sector: %llu ", (unsigned long long) lastLBA);
printf("(at %s)\n", BytesToSI(lastLBA * blockSize, temp));
cout << "First sector: " << firstLBA << " (at "
<< BytesToSI(firstLBA * blockSize) << ")\n";
cout << "Last sector: " << lastLBA << " (at "
<< BytesToSI(lastLBA * blockSize) << ")\n";
size = (lastLBA - firstLBA + 1);
printf("Partition size: %llu sectors ", (unsigned long long) size);
printf("(%s)\n", BytesToSI(size * ((uint64_t) blockSize), temp));
printf("Attribute flags: %016llx\n", (unsigned long long) attributes);
printf("Partition name: ");
i = 0;
while ((name[i] != '\0') && (i < NAME_SIZE)) {
printf("%c", name[i]);
i += 2;
} // while
printf("\n");
cout << "Partition size: " << size << " sectors ("
<< BytesToSI(size * ((uint64_t) blockSize)) << ")\n";
cout << "Attribute flags: ";
cout.fill('0');
cout.width(16);
cout << right;
cout << hex;
cout << attributes << "\n";
cout << left;
cout << dec;
cout << "Partition name: " << GetName() << "\n";
} // if
} // GPTPart::ShowDetails()
@@ -194,14 +196,14 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
// Change the type code on the partition.
void GPTPart::ChangeType(void) {
char typeName[255], line[255];
char line[255];
char* junk;
int typeNum = 0xFFFF;
GUIDData newType;
printf("Current type is '%s'\n", GetNameType().c_str());
cout << "Current type is '" << GetNameType() << "'\n";
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
printf("Hex code (L to show codes, 0 to enter raw code, Enter = 0700): ");
cout << "Hex code (L to show codes, 0 to enter raw code, Enter = 0700): ";
junk = fgets(line, 255, stdin);
sscanf(line, "%X", &typeNum);
if ((line[0] == 'L') || (line[0] == 'l'))
@@ -215,25 +217,24 @@ void GPTPart::ChangeType(void) {
else // user wants to enter the GUID directly, so do that
newType = GetGUID();
partitionType = newType;
printf("Changed type of partition to '%s'\n",
typeHelper.GUIDToName(partitionType, typeName));
cout << "Changed type of partition to '" << typeHelper.GUIDToName(partitionType) << "'\n";
} // GPTPart::ChangeType()
// Set the name for a partition to theName, or prompt for a name if
// theName is a NULL pointer. Note that theName is a standard C-style
// theName is empty. Note that theName is a standard C++-style ASCII
// string, although the GUID partition definition requires a UTF-16LE
// string. This function creates a simple-minded copy for this.
void GPTPart::SetName(unsigned char* theName) {
void GPTPart::SetName(string theName) {
char newName[NAME_SIZE]; // New name
char* junk;
char *junk;
int i;
// Blank out new name string, just to be on the safe side....
for (i = 0; i < NAME_SIZE; i++)
newName[i] = '\0';
if (theName == NULL) { // No name specified, so get one from the user
printf("Enter name: ");
if (theName == "") { // No name specified, so get one from the user
cout << "Enter name: ";
junk = fgets(newName, NAME_SIZE / 2, stdin);
// Input is likely to include a newline, so remove it....
@@ -241,7 +242,7 @@ void GPTPart::SetName(unsigned char* theName) {
if (newName[i - 1] == '\n')
newName[i - 1] = '\0';
} else {
strcpy(newName, (char*) theName);
strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str());
} // if
// Copy the C-style ASCII string from newName into a form that the GPT

View File

@@ -69,7 +69,7 @@ class GPTPart {
void SetFirstLBA(uint64_t f) {firstLBA = f;}
void SetLastLBA(uint64_t l) {lastLBA = l;}
void SetAttributes(uint64_t a) {attributes = a;}
void SetName(unsigned char* n);
void SetName(string n);
// Additional functions
GPTPart & operator=(const GPTPart & orig);

84
mbr.cc
View File

@@ -18,6 +18,7 @@
#include <time.h>
#include <sys/stat.h>
#include <errno.h>
#include <iostream>
#include "mbr.h"
#include "support.h"
@@ -32,7 +33,7 @@ using namespace std;
MBRData::MBRData(void) {
blockSize = SECTOR_SIZE;
diskSize = 0;
strcpy(device, "");
device = "";
state = invalid;
srand((unsigned int) time(NULL));
numHeads = MAX_HEADS;
@@ -40,10 +41,10 @@ MBRData::MBRData(void) {
EmptyMBR();
} // MBRData default constructor
MBRData::MBRData(char *filename) {
MBRData::MBRData(string filename) {
blockSize = SECTOR_SIZE;
diskSize = 0;
strcpy(device, filename);
device = filename;
state = invalid;
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
@@ -52,7 +53,7 @@ MBRData::MBRData(char *filename) {
// Try to read the specified partition table, but if it fails....
if (!ReadMBRData(filename)) {
EmptyMBR();
strcpy(device, "");
device = "";
} // if
} // MBRData(char *filename) constructor
@@ -67,7 +68,7 @@ MBRData::~MBRData(void) {
// 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 MBRData::ReadMBRData(char* deviceFilename) {
int MBRData::ReadMBRData(string deviceFilename) {
int fd, allOK = 1;
if (myDisk->OpenForRead(deviceFilename)) {
@@ -77,7 +78,7 @@ int MBRData::ReadMBRData(char* deviceFilename) {
} // if
if (allOK)
strcpy(device, deviceFilename);
device = deviceFilename;
return allOK;
} // MBRData::ReadMBRData(char* deviceFilename)
@@ -101,7 +102,7 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
if (myDisk->Read(&tempMBR, 512))
err = 0;
if (err) {
fprintf(stderr, "Problem reading disk in MBRData::ReadMBRData!\n");
cerr << "Problem reading disk in MBRData::ReadMBRData!\n";
} else {
for (i = 0; i < 440; i++)
code[i] = tempMBR.code[i];
@@ -152,7 +153,7 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
logicalNum = ReadLogicalPart(partitions[i].firstLBA, UINT32_C(0), 4);
if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
allOK = 0;
fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
cerr << "Error reading logical partitions! List may be truncated!\n";
} // if maxLogicals valid
} // if primary partition is extended
} // for primary partition loop
@@ -202,14 +203,13 @@ int MBRData::ReadLogicalPart(uint32_t extendedStart,
// function as of GPT fdisk version 0.5.0 doesn't do so.
if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
offset = (uint64_t) (extendedStart + diskOffset);
// if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
if (myDisk->Seek(offset) == 0) { // seek to EBR record
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
cerr << "Unable to seek to " << offset << "! Aborting!\n";
partNum = -1;
}
if (myDisk->Read(&ebr, 512) != 512) { // Load the data....
fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
(unsigned long) offset);
cerr << "Error seeking to or reading logical partition data from " << offset
<< "!\nAborting!\n";
partNum = -1;
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
ReverseBytes(&ebr.MBRSignature, 2);
@@ -221,8 +221,14 @@ int MBRData::ReadLogicalPart(uint32_t extendedStart,
if (ebr.MBRSignature != MBR_SIGNATURE) {
partNum = -1;
fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
(unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
cerr << "MBR signature in 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
// Copy over the basic data....
@@ -297,11 +303,11 @@ int MBRData::WriteMBRData(DiskIO *theDisk) {
if (allOK && theDisk->Seek(0)) {
if (theDisk->Write(&tempMBR, 512) != 512) {
allOK = 0;
fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
cerr << "Warning! Error " << errno << " when saving MBR!\n";
} // if
} else {
allOK = 0;
fprintf(stderr, "Warning! Error %d when seeking to MBR to write it!\n", errno);
cerr << "Warning! Error " << errno << " when seeking to MBR to write it!\n";
} // if/else
theDisk->Close();
@@ -318,8 +324,8 @@ int MBRData::WriteMBRData(DiskIO *theDisk) {
return allOK;
} // MBRData::WriteMBRData(DiskIO theDisk)
int MBRData::WriteMBRData(char* deviceFilename) {
strcpy(device, deviceFilename);
int MBRData::WriteMBRData(string deviceFilename) {
device = deviceFilename;
return WriteMBRData();
} // MBRData::WriteMBRData(char* deviceFilename)
@@ -335,22 +341,34 @@ void MBRData::DisplayMBRData(void) {
char tempStr[255];
char bootCode;
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
printf("MBR partitions:\n");
printf("Number\t Boot\t Start (sector)\t Length (sectors)\tType\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";
cout << "Number\t Boot\t Start (sector)\t Length (sectors)\tType\n";
for (i = 0; i < MAX_MBR_PARTS; i++) {
if (partitions[i].lengthLBA != 0) {
if (partitions[i].status && 0x80) // it's bootable
bootCode = '*';
else
bootCode = ' ';
printf("%4d\t %c\t%13lu\t%15lu \t0x%02X\n", i + 1, bootCode,
(unsigned long) partitions[i].firstLBA,
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
cout.fill(' ');
cout.width(4);
cout << i + 1 << "\t " << bootCode << "\t";
cout.width(13);
cout << partitions[i].firstLBA << "\t";
cout.width(15);
cout << partitions[i].lengthLBA << " \t0x";
cout.width(2);
cout.fill('0');
cout << hex << (int) partitions[i].partitionType << dec << "\n";
} // if
cout.fill(' ');
} // for
printf("\nDisk size is %llu sectors ", (unsigned long long) diskSize);
printf("(%s)\n", BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
cout << "\nDisk size is " << diskSize << " sectors ("
<< BytesToSI(diskSize * (uint64_t) blockSize) << "\n";
} // MBRData::DisplayMBRData()
// Displays the state, as a word, on stdout. Used for debugging & to
@@ -358,19 +376,19 @@ void MBRData::DisplayMBRData(void) {
void MBRData::ShowState(void) {
switch (state) {
case invalid:
printf(" MBR: not present\n");
cout << " MBR: not present\n";
break;
case gpt:
printf(" MBR: protective\n");
cout << " MBR: protective\n";
break;
case hybrid:
printf(" MBR: hybrid\n");
cout << " MBR: hybrid\n";
break;
case mbr:
printf(" MBR: MBR only\n");
cout << " MBR: MBR only\n";
break;
default:
printf("\a MBR: unknown -- bug!\n");
cout << "\a MBR: unknown -- bug!\n";
break;
} // switch
} // MBRData::ShowState()
@@ -390,7 +408,7 @@ void MBRData::SetCHSGeom(uint32_t h, uint32_t s) {
numHeads = h;
numSecspTrack = s;
} else {
printf("Warning! Attempt to set invalid CHS geometry!\n");
cout << "Warning! Attempt to set invalid CHS geometry!\n";
} // if/else
} // MBRData::SetCHSGeom()
@@ -807,7 +825,7 @@ GPTPart MBRData::AsGPT(int i) {
newPart.SetType(((uint16_t) origType) * 0x0100);
newPart.SetUniqueGUID(1);
newPart.SetAttributes(0);
newPart.SetName((unsigned char*) newPart.GetNameType().c_str());
newPart.SetName(newPart.GetNameType());
} // if not extended, protective, or non-existent
} // if (origPart != NULL)
return newPart;

8
mbr.h
View File

@@ -71,16 +71,16 @@ protected:
uint64_t numHeads; // number of heads, in CHS scheme
uint64_t numSecspTrack; // number of sectors per track, in CHS scheme
DiskIO* myDisk;
char device[256];
string device;
MBRValidity state;
struct MBRRecord* GetPartition(int i); // Return primary or logical partition
public:
MBRData(void);
MBRData(char* deviceFilename);
MBRData(string deviceFilename);
~MBRData(void);
// File I/O functions...
int ReadMBRData(char* deviceFilename);
int ReadMBRData(string deviceFilename);
void ReadMBRData(DiskIO * theDisk, int checkBlockSize = 1);
// ReadLogicalPart() returns last partition # read to logicals[] array,
// or -1 if there was a problem....
@@ -88,7 +88,7 @@ public:
int partNum);
int WriteMBRData(void);
int WriteMBRData(DiskIO *theDisk);
int WriteMBRData(char* deviceFilename);
int WriteMBRData(string deviceFilename);
// Display data for user...
void DisplayMBRData(void);

View File

@@ -11,6 +11,7 @@
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <iostream>
#include "parttypes.h"
using namespace std;
@@ -236,20 +237,24 @@ int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
void PartTypes::ShowTypes(void) {
int colCount = 1; // column count
AType* thisType = allTypes;
char tempStr[20];
cout.unsetf(ios::uppercase);
while (thisType != NULL) {
if (thisType->display == 1) { // show it
strncpy(tempStr, thisType->name, 19);
tempStr[19] = '\0';
printf("%04x %-19s ", thisType->MBRType, tempStr);
cout.fill('0');
cout.width(4);
cout << hex << thisType->MBRType << " ";
cout.fill(' ');
cout.setf(ios::left);
cout.width(19);
cout << ((string) thisType->name).substr(0, 19) << " ";
if ((colCount % 3) == 0)
printf("\n");
cout << "\n";
colCount++;
} // if
thisType = thisType->next;
} // while
printf("\n");
cout << "\n";
} // PartTypes::ShowTypes()
// Returns 1 if code is a valid extended MBR code, 0 if it's not
@@ -267,21 +272,24 @@ int PartTypes::Valid(uint16_t code) {
} // PartTypes::Valid()
// Convert a GUID code to a name.
char* PartTypes::GUIDToName(struct GUIDData typeCode, char typeName[]) {
string PartTypes::GUIDToName(struct GUIDData typeCode) {
AType* theItem = allTypes;
int found = 0;
string typeName;
while ((theItem != NULL) && (!found)) {
if ((theItem->GUIDType.data1 == typeCode.data1) &&
(theItem->GUIDType.data2 == typeCode.data2)) { // found it!
strcpy(typeName, theItem->name);
// strcpy(typeName, theItem->name);
typeName = theItem->name;
found = 1;
} else {
theItem = theItem->next;
} // if/else
} // while
if (!found) {
strcpy(typeName, (char*) "Unknown");
typeName = "Unknown";
// strcpy(typeName, (char*) "Unknown");
} // if (!found)
return typeName;
} // PartTypes::GUIDToName()
@@ -310,8 +318,11 @@ struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
} // if/else
} // while
if (!found) {
printf("Exact type match not found for type code %04X; assigning type code for\n'Linux/Windows data'\n",
ID);
cout.setf(ios::uppercase);
cout.fill('0');
cout << "Exact type match not found for type code ";
cout.width(4);
cout << hex << ID << "; assigning type code for\n'Linux/Windows data'\n" << dec;
} // if (!found)
return theGUID;
} // PartTypes::IDToGUID()

View File

@@ -4,7 +4,7 @@
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include "support.h"
#ifndef __PARTITION_TYPES
@@ -39,7 +39,7 @@ public:
const char* name, int toDisplay = 1);
void ShowTypes(void);
int Valid(uint16_t);
char* GUIDToName(struct GUIDData typeCode, char typeName[]);
string GUIDToName(struct GUIDData typeCode);
struct GUIDData IDToGUID(uint16_t ID);
uint16_t GUIDToID(struct GUIDData);
};

View File

@@ -13,6 +13,7 @@
#include <string>
#include <popt.h>
#include <errno.h>
#include <iostream>
#include "mbr.h"
#include "gpt.h"
#include "support.h"
@@ -87,7 +88,7 @@ int main(int argc, char *argv[]) {
pretend = 1;
break;
case 'V':
printf("GPT fdisk (sgdisk) version %s\n\n", GPTFDISK_VERSION);
cout << "GPT fdisk (sgdisk) version " << GPTFDISK_VERSION << "\n\n";
break;
default:
break;
@@ -102,7 +103,7 @@ int main(int argc, char *argv[]) {
if (device != NULL) {
theGPT.JustLooking(); // reset as necessary
theGPT.BeQuiet(); // Tell called functions to be less verbose & interactive
if (theGPT.LoadPartitions(device)) {
if (theGPT.LoadPartitions((string) device)) {
if ((theGPT.WhichWasUsed() == use_mbr) || (theGPT.WhichWasUsed() == use_bsd))
saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
while ((opt = poptGetNextOpt(poptCon)) > 0) {
@@ -117,11 +118,11 @@ int main(int argc, char *argv[]) {
case 'c':
theGPT.JustLooking(0);
partNum = (int) GetInt(partName, 1) - 1;
if (theGPT.SetName(partNum, (char*) GetString(partName, 2).c_str())) {
if (theGPT.SetName(partNum, GetString(partName, 2))) {
saveData = 1;
} else {
fprintf(stderr, "Unable set set partition %d's name to '%s'!\n",
partNum + 1, GetString(partName, 2).c_str());
cerr << "Unable set set partition " << partNum + 1
<< "'s name to '" << GetString(partName, 2) << "'!\n";
neverSaveData = 1;
} // if/else
free(partName);
@@ -129,7 +130,7 @@ int main(int argc, char *argv[]) {
case 'd':
theGPT.JustLooking(0);
if (theGPT.DeletePartition(deletePartNum - 1) == 0) {
fprintf(stderr, "Error %d deleting partition!\n", errno);
cerr << "Error " << errno << " deleting partition!\n";
neverSaveData = 1;
} else saveData = 1;
break;
@@ -139,10 +140,10 @@ int main(int argc, char *argv[]) {
saveData = 1;
break;
case 'E':
printf("%llu\n", (unsigned long long) theGPT.FindLastAvailable(theGPT.FindFirstInLargest()));
cout << theGPT.FindLastAvailable(theGPT.FindFirstInLargest()) << "\n";
break;
case 'f':
printf("%llu\n", (unsigned long long) theGPT.FindFirstInLargest());
cout << theGPT.FindFirstInLargest() << "\n";
break;
case 'g':
theGPT.JustLooking(0);
@@ -153,12 +154,12 @@ int main(int argc, char *argv[]) {
theGPT.ShowPartDetails(infoPartNum - 1);
break;
case 'l':
if (theGPT.LoadGPTBackup(backupFile) == 1)
if (theGPT.LoadGPTBackup((string) backupFile) == 1)
saveData = 1;
else {
saveData = 0;
neverSaveData = 1;
fprintf(stderr, "Error loading backup file!\n");
cerr << "Error loading backup file!\n";
} // else
free(backupFile);
break;
@@ -172,8 +173,8 @@ int main(int argc, char *argv[]) {
if (theGPT.CreatePartition(partNum, startSector, endSector)) {
saveData = 1;
} else {
fprintf(stderr, "Could not create partition %d from %llu to %llu!\n",
partNum, startSector, endSector);
cerr << "Could not create partition " << partNum << " from "
<< startSector << " to " << endSector << "\n";
neverSaveData = 1;
} // if/else
free(newPartInfo);
@@ -208,8 +209,8 @@ int main(int argc, char *argv[]) {
if (theGPT.ChangePartType(partNum, hexCode)) {
saveData = 1;
} else {
fprintf(stderr, "Could not change partition %d's type code to %x!\n",
partNum + 1, hexCode);
cerr << "Could not change partition " << partNum + 1
<< "'s type code to " << hex << hexCode << "!\n" << dec;
neverSaveData = 1;
} // if/else
free(typeCode);
@@ -228,18 +229,18 @@ int main(int argc, char *argv[]) {
saveNonGPT = 0;
break;
default:
printf("Unknown option (-%c)!\n", opt);
cerr << "Unknown option (-" << opt << ")!\n";
break;
} // switch
} // while
if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend))
theGPT.SaveGPTData(1);
if (saveData && (!saveNonGPT)) {
printf("Non-GPT disk; not saving changes. Use -g to override.\n");
cout << "Non-GPT disk; not saving changes. Use -g to override.\n";
retval = 3;
} // if
if (neverSaveData) {
printf("Error encountered; not saving changes.\n");
cerr << "Error encountered; not saving changes.\n";
retval = 4;
} // if
} else { // if loaded OK
@@ -267,8 +268,6 @@ uint64_t GetInt(char* argument, int itemNum) {
endPos--;
sscanf(Info.substr(startPos, endPos - startPos + 1).c_str(), "%llu", &retval);
/* printf("In GetInt(), startPos = %d, endPos = %d, retval = %llu\n", startPos,
endPos, (unsigned long long) retval); */
return retval;
} // GetInt()

View File

@@ -10,11 +10,13 @@
#define __STDC_CONSTANT_MACROS
#include <stdio.h>
#include <string>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <string>
#include <iostream>
#include "support.h"
#include <sys/types.h>
@@ -33,26 +35,25 @@ using namespace std;
// If user provides no input, def (default value) is returned.
// (If def is outside of the low-high range, an explicit response
// is required.)
int GetNumber(int low, int high, int def, const char prompt[]) {
int GetNumber(int low, int high, int def, const string & prompt) {
int response, num;
char line[255];
char* junk;
if (low != high) { // bother only if low and high differ...
response = low - 1; // force one loop by setting response outside range
while ((response < low) || (response > high)) {
printf("%s", prompt);
junk = fgets(line, 255, stdin);
cout << prompt;
cin.getline(line, 255);
num = sscanf(line, "%d", &response);
if (num == 1) { // user provided a response
if ((response < low) || (response > high))
printf("Value out of range\n");
cout << "Value out of range\n";
} else { // user hit enter; return default
response = def;
} // if/else
} // while
} else { // low == high, so return this value
printf("Using %d\n", low);
cout << "Using " << low << "\n";
response = low;
} // else
return (response);
@@ -62,10 +63,10 @@ int GetNumber(int low, int high, int def, const char prompt[]) {
char GetYN(void) {
char line[255];
char response = '\0';
char* junk;
char *junk;
while ((response != 'Y') && (response != 'N')) {
printf("(Y/N): ");
cout << "(Y/N): ";
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &response);
if (response == 'y') response = 'Y';
@@ -81,18 +82,17 @@ char GetYN(void) {
// If a "-" prefix is used, use the high value minus the user-
// specified number of sectors (or KiB, MiB, etc.). Use the def
//value as the default if the user just hits Enter
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[]) {
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt) {
unsigned long long response;
int num, plusFlag = 0;
uint64_t mult = 1;
char suffix;
char line[255];
char* junk;
response = low - 1; // Ensure one pass by setting a too-low initial value
while ((response < low) || (response > high)) {
printf("%s", prompt);
junk = fgets(line, 255, stdin);
cout << prompt;
cin.getline(line, 255);
// Remove leading spaces, if present
while (line[0] == ' ')
@@ -164,65 +164,65 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[])
// Takes a size in bytes (in size) and converts this to a size in
// SI units (KiB, MiB, GiB, TiB, or PiB), returned in C++ string
// form
char* BytesToSI(uint64_t size, char theValue[]) {
char units[8];
string BytesToSI(uint64_t size) {
string units;
char theValue[99];
float sizeInSI;
if (theValue != NULL) {
sizeInSI = (float) size;
strcpy (units, " bytes");
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
strcpy(units, " KiB");
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
strcpy(units, " MiB");
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
strcpy(units, " GiB");
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
strcpy(units, " TiB");
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
strcpy(units, " PiB");
} // if
if (strcmp(units, " bytes") == 0) { // in bytes, so no decimal point
sprintf(theValue, "%1.0f%s", sizeInSI, units);
} else {
sprintf(theValue, "%1.1f%s", sizeInSI, units);
} // if/else
theValue[0] = '\0';
sizeInSI = (float) size;
units = " bytes";
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
units = " KiB";
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
units = " MiB";
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
units = " GiB";
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
units = " TiB";
} // if
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
units = " PiB";
} // if
if (units == " bytes") { // in bytes, so no decimal point
sprintf(theValue, "%1.0f%s", sizeInSI, units.c_str());
} else {
sprintf(theValue, "%1.1f%s", sizeInSI, units.c_str());
} // if/else
return theValue;
} // BlocksToSI()
// Return a plain-text name for a partition type.
// Convert a GUID to a string representation, suitable for display
// to humans....
char* GUIDToStr(struct GUIDData theGUID, char* theString) {
string GUIDToStr(struct GUIDData theGUID) {
unsigned long long blocks[11], block;
char theString[40];
if (theString != NULL) {
blocks[0] = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF));
blocks[1] = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32;
blocks[2] = (theGUID.data1 & UINT64_C(0xFFFF000000000000)) >> 48;
blocks[3] = (theGUID.data2 & UINT64_C(0x00000000000000FF));
blocks[4] = (theGUID.data2 & UINT64_C(0x000000000000FF00)) >> 8;
blocks[5] = (theGUID.data2 & UINT64_C(0x0000000000FF0000)) >> 16;
blocks[6] = (theGUID.data2 & UINT64_C(0x00000000FF000000)) >> 24;
blocks[7] = (theGUID.data2 & UINT64_C(0x000000FF00000000)) >> 32;
blocks[8] = (theGUID.data2 & UINT64_C(0x0000FF0000000000)) >> 40;
blocks[9] = (theGUID.data2 & UINT64_C(0x00FF000000000000)) >> 48;
blocks[10] = (theGUID.data2 & UINT64_C(0xFF00000000000000)) >> 56;
sprintf(theString,
"%08llX-%04llX-%04llX-%02llX%02llX-%02llX%02llX%02llX%02llX%02llX%02llX",
blocks[0], blocks[1], blocks[2], blocks[3], blocks[4], blocks[5],
blocks[6], blocks[7], blocks[8], blocks[9], blocks[10]);
} // if
theString[0] = '\0';;
blocks[0] = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF));
blocks[1] = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32;
blocks[2] = (theGUID.data1 & UINT64_C(0xFFFF000000000000)) >> 48;
blocks[3] = (theGUID.data2 & UINT64_C(0x00000000000000FF));
blocks[4] = (theGUID.data2 & UINT64_C(0x000000000000FF00)) >> 8;
blocks[5] = (theGUID.data2 & UINT64_C(0x0000000000FF0000)) >> 16;
blocks[6] = (theGUID.data2 & UINT64_C(0x00000000FF000000)) >> 24;
blocks[7] = (theGUID.data2 & UINT64_C(0x000000FF00000000)) >> 32;
blocks[8] = (theGUID.data2 & UINT64_C(0x0000FF0000000000)) >> 40;
blocks[9] = (theGUID.data2 & UINT64_C(0x00FF000000000000)) >> 48;
blocks[10] = (theGUID.data2 & UINT64_C(0xFF00000000000000)) >> 56;
sprintf(theString,
"%08llX-%04llX-%04llX-%02llX%02llX-%02llX%02llX%02llX%02llX%02llX%02llX",
blocks[0], blocks[1], blocks[2], blocks[3], blocks[4], blocks[5],
blocks[6], blocks[7], blocks[8], blocks[9], blocks[10]);
return theString;
} // GUIDToStr()
@@ -234,10 +234,10 @@ GUIDData GetGUID(void) {
char* junk;
GUIDData theGUID;
printf("\nA GUID is entered in five segments of from two to six bytes, with\n"
"dashes between segments.\n");
printf("Enter the entire GUID, a four-byte hexadecimal number for the first segment, or\n"
"'R' to generate the entire GUID randomly: ");
cout << "\nA GUID is entered in five segments of from two to six bytes, with\n"
<< "dashes between segments.\n";
cout << "Enter the entire GUID, a four-byte hexadecimal number for the first segment, or\n"
<< "'R' to generate the entire GUID randomly: ";
junk = fgets(temp, 255, stdin);
// If user entered 'r' or 'R', generate GUID randomly....
@@ -280,17 +280,17 @@ GUIDData GetGUID(void) {
// entry....
if (entered == 0) {
sscanf(temp, "%llx", &part1);
printf("Enter a two-byte hexadecimal number for the second segment: ");
cout << "Enter a two-byte hexadecimal number for the second segment: ";
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part2);
printf("Enter a two-byte hexadecimal number for the third segment: ");
cout << "Enter a two-byte hexadecimal number for the third segment: ";
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part3);
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
printf("Enter a two-byte hexadecimal number for the fourth segment: ");
cout << "Enter a two-byte hexadecimal number for the fourth segment: ";
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part4);
printf("Enter a six-byte hexadecimal number for the fifth segment: ");
cout << "Enter a six-byte hexadecimal number for the fifth segment: ";
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part5);
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
@@ -303,7 +303,7 @@ GUIDData GetGUID(void) {
((part5 & UINT64_C(0x00000000000000FF)) << 56);
entered = 1;
} // if/else
printf("New GUID: %s\n", GUIDToStr(theGUID, temp));
cout << "New GUID: " << GUIDToStr(theGUID) << "\n";
return theGUID;
} // GetGUID()
@@ -324,17 +324,16 @@ int IsLittleEndian(void) {
// Reverse the byte order of theValue; numBytes is number of bytes
void ReverseBytes(void* theValue, int numBytes) {
char* origValue;
char* tempValue;
char* tempValue = NULL;
int i;
origValue = (char*) theValue;
tempValue = (char*) malloc(numBytes);
for (i = 0; i < numBytes; i++)
tempValue[i] = origValue[i];
for (i = 0; i < numBytes; i++)
origValue[i] = tempValue[numBytes - i - 1];
free(tempValue);
if (tempValue != NULL) {
memcpy(tempValue, theValue, numBytes);
for (i = 0; i < numBytes; i++)
((char*) theValue)[i] = tempValue[numBytes - i - 1];
free(tempValue);
} // if
} // ReverseBytes()
// Compute (2 ^ value). Given the return type, value must be 63 or less.

View File

@@ -4,7 +4,7 @@
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#ifndef __GPTSUPPORT
#define __GPTSUPPORT
@@ -35,6 +35,9 @@
#define APM_SIGNATURE1 UINT64_C(0x00004D5000000000)
#define APM_SIGNATURE2 UINT64_C(0x0000535400000000)
// Maximum line length ignored on some input functions
#define MAX_IGNORED 999
/**************************
* Some GPT constants.... *
**************************/
@@ -58,11 +61,11 @@ struct GUIDData {
static char theFile[255];
int GetNumber(int low, int high, int def, const char prompt[]);
int GetNumber(int low, int high, int def, const string & prompt);
char GetYN(void);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[]);
char* BytesToSI(uint64_t size, char theValue[]);
char* GUIDToStr(struct GUIDData theGUID, char* theString);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt);
string BytesToSI(uint64_t size);
string GUIDToStr(struct GUIDData theGUID);
GUIDData GetGUID(void);
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue