From fed16d043a14e8b86c97a6413aec7281fefcbcb5 Mon Sep 17 00:00:00 2001 From: srs5694 <srs5694@users.sourceforge.net> Date: Wed, 27 Jan 2010 23:03:40 -0500 Subject: [PATCH] Misc. updates and bug fixes --- CHANGELOG | 4 + attributes.cc | 38 +-- attributes.h | 2 +- bsd.cc | 117 +++++---- bsd.h | 5 +- diskio-unix.cc | 39 ++- diskio.cc | 6 +- diskio.h | 2 - gdisk.cc | 185 ++++++------- gpt.cc | 701 ++++++++++++++++++++++++------------------------- gpt.h | 16 +- gptpart.cc | 111 ++++---- gptpart.h | 2 +- mbr.cc | 84 +++--- mbr.h | 8 +- parttypes.cc | 33 ++- parttypes.h | 4 +- sgdisk.cc | 37 ++- support.cc | 157 ++++++----- support.h | 13 +- 20 files changed, 803 insertions(+), 761 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c09020a..a5a7c84 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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.) diff --git a/attributes.cc b/attributes.cc index 73560d6..9bdd428 100644 --- a/attributes.cc +++ b/attributes.cc @@ -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); diff --git a/attributes.h b/attributes.h index 38313d7..647c205 100644 --- a/attributes.h +++ b/attributes.h @@ -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); diff --git a/bsd.cc b/bsd.cc index 7052001..1db68ea 100644 --- a/bsd.cc +++ b/bsd.cc @@ -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; - - if (device != NULL) { - if (myDisk == NULL) { - myDisk = new DiskIO; - tempMyDisk = 1; - } // if - if (myDisk->OpenForRead(device)) { - ReadBSDData(myDisk, startSector, endSector); +// 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 != "") { + 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() diff --git a/bsd.h b/bsd.h index 77d3d3c..54f5899 100644 --- a/bsd.h +++ b/bsd.h @@ -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 diff --git a/diskio-unix.cc b/diskio-unix.cc index 573af56..a72c7ce 100644 --- a/diskio-unix.cc +++ b/diskio-unix.cc @@ -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 diff --git a/diskio.cc b/diskio.cc index 3fc3726..d1d0c3c 100644 --- a/diskio.cc +++ b/diskio.cc @@ -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 diff --git a/diskio.h b/diskio.h index 2435cc5..8b752ed 100644 --- a/diskio.h +++ b/diskio.h @@ -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); diff --git a/gdisk.cc b/gdisk.cc index 0809c3c..2329fac 100644 --- a/gdisk.cc +++ b/gdisk.cc @@ -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() diff --git a/gpt.cc b/gpt.cc index 867c3ff..e5c9852 100644 --- a/gpt.cc +++ b/gpt.cc @@ -18,6 +18,7 @@ #include <time.h> #include <sys/stat.h> #include <errno.h> +#include <iostream> #include "crc32.h" #include "gpt.h" #include "bsd.h" @@ -40,7 +41,7 @@ GPTData::GPTData(void) { diskSize = 0; partitions = NULL; state = gpt_valid; - strcpy(device, ""); + device = ""; justLooking = 0; mainCrcOk = 0; secondCrcOk = 0; @@ -57,12 +58,12 @@ GPTData::GPTData(void) { } // GPTData default constructor // The following constructor loads GPT data from a device file -GPTData::GPTData(char* filename) { +GPTData::GPTData(string filename) { blockSize = SECTOR_SIZE; // set a default diskSize = 0; partitions = NULL; state = gpt_invalid; - strcpy(device, ""); + device = ""; justLooking = 0; mainCrcOk = 0; secondCrcOk = 0; @@ -77,7 +78,7 @@ GPTData::GPTData(char* filename) { mainHeader.numParts = 0; if (!LoadPartitions(filename)) exit(2); -} // GPTData(char* filename) constructor +} // GPTData(string filename) constructor // Destructor GPTData::~GPTData(void) { @@ -102,116 +103,109 @@ int GPTData::Verify(void) { // First, check for CRC errors in the GPT data.... if (!mainCrcOk) { problems++; - printf("\nProblem: The CRC for the main GPT header is invalid. The main GPT header may\n" - "be corrupt. Consider loading the backup GPT header to rebuild the main GPT\n" - "header ('b' on the recovery & transformation menu). This report may be a false\n" - "alarm if you've already corrected other problems.\n"); + cout << "\nProblem: The CRC for the main GPT header is invalid. The main GPT header may\n" + << "be corrupt. Consider loading the backup GPT header to rebuild the main GPT\n" + << "header ('b' on the recovery & transformation menu). This report may be a false\n" + << "alarm if you've already corrected other problems.\n"; } // if if (!mainPartsCrcOk) { problems++; - printf("\nProblem: The CRC for the main partition table is invalid. This table may be\n" - "corrupt. Consider loading the backup partition table ('c' on the recovery &\n" - "transformation menu). This report may be a false alarm if you've already\n" - "corrected other problems.\n"); + cout << "\nProblem: The CRC for the main partition table is invalid. This table may be\n" + << "corrupt. Consider loading the backup partition table ('c' on the recovery &\n" + << "transformation menu). This report may be a false alarm if you've already\n" + << "corrected other problems.\n"; } // if if (!secondCrcOk) { problems++; - printf("\nProblem: The CRC for the backup GPT header is invalid. The backup GPT header\n" - "may be corrupt. Consider using the main GPT header to rebuild the backup GPT\n" - "header ('d' on the recovery & transformation menu). This report may be a false\n" - "alarm if you've already corrected other problems.\n"); + cout << "\nProblem: The CRC for the backup GPT header is invalid. The backup GPT header\n" + << "may be corrupt. Consider using the main GPT header to rebuild the backup GPT\n" + << "header ('d' on the recovery & transformation menu). This report may be a false\n" + << "alarm if you've already corrected other problems.\n"; } // if if (!secondPartsCrcOk) { problems++; - printf("\nCaution: The CRC for the backup partition table is invalid. This table may\n" - "be corrupt. This program will automatically create a new backup partition\n" - "table when you save your partitions.\n"); + cout << "\nCaution: The CRC for the backup partition table is invalid. This table may\n" + << "be corrupt. This program will automatically create a new backup partition\n" + << "table when you save your partitions.\n"; } // if // Now check that the main and backup headers both point to themselves.... if (mainHeader.currentLBA != 1) { problems++; - printf("\nProblem: The main header's self-pointer doesn't point to itself. This problem\n" - "is being automatically corrected, but it may be a symptom of more serious\n" - "problems. Think carefully before saving changes with 'w' or using this disk.\n"); + cout << "\nProblem: The main header's self-pointer doesn't point to itself. This problem\n" + << "is being automatically corrected, but it may be a symptom of more serious\n" + << "problems. Think carefully before saving changes with 'w' or using this disk.\n"; mainHeader.currentLBA = 1; } // if if (secondHeader.currentLBA != (diskSize - UINT64_C(1))) { problems++; - printf("\nProblem: The secondary header's self-pointer indicates that it doesn't reside\n" - "at the end of the disk. If you've added a disk to a RAID array, use the 'e'\n" - "option on the experts' menu to adjust the secondary header's and partition\n" - "table's locations.\n"); + cout << "\nProblem: The secondary header's self-pointer indicates that it doesn't reside\n" + << "at the end of the disk. If you've added a disk to a RAID array, use the 'e'\n" + << "option on the experts' menu to adjust the secondary header's and partition\n" + << "table's locations.\n"; } // if // Now check that critical main and backup GPT entries match each other if (mainHeader.currentLBA != secondHeader.backupLBA) { problems++; - printf("\nProblem: main GPT header's current LBA pointer (%llu) doesn't\n" - "match the backup GPT header's LBA pointer(%llu).\n", - (unsigned long long) mainHeader.currentLBA, - (unsigned long long) secondHeader.backupLBA); + cout << "\nProblem: main GPT header's current LBA pointer (" << mainHeader.currentLBA + << ") doesn't\nmatch the backup GPT header's alternate LBA pointer(" + << secondHeader.backupLBA << ").\n"; } // if if (mainHeader.backupLBA != secondHeader.currentLBA) { problems++; - printf("\nProblem: main GPT header's backup LBA pointer (%llu) doesn't\n" - "match the backup GPT header's current LBA pointer (%llu).\n" - "The 'e' option on the experts' menu may fix this problem.\n", - (unsigned long long) mainHeader.backupLBA, - (unsigned long long) secondHeader.currentLBA); + cout << "\nProblem: main GPT header's backup LBA pointer (" << mainHeader.backupLBA + << ") doesn't\nmatch the backup GPT header's current LBA pointer (" + << secondHeader.currentLBA << ").\n" + << "The 'e' option on the experts' menu may fix this problem.\n"; } // if if (mainHeader.firstUsableLBA != secondHeader.firstUsableLBA) { problems++; - printf("\nProblem: main GPT header's first usable LBA pointer (%llu) doesn't\n" - "match the backup GPT header's first usable LBA pointer (%llu)\n", - (unsigned long long) mainHeader.firstUsableLBA, - (unsigned long long) secondHeader.firstUsableLBA); + cout << "\nProblem: main GPT header's first usable LBA pointer (" << mainHeader.firstUsableLBA + << ") doesn't\nmatch the backup GPT header's first usable LBA pointer (" + << secondHeader.firstUsableLBA << ")\n"; } // if if (mainHeader.lastUsableLBA != secondHeader.lastUsableLBA) { problems++; - printf("\nProblem: main GPT header's last usable LBA pointer (%llu) doesn't\n" - "match the backup GPT header's last usable LBA pointer (%llu)\n", - (unsigned long long) mainHeader.lastUsableLBA, - (unsigned long long) secondHeader.lastUsableLBA); - printf("The 'e' option on the experts' menu can probably fix this problem.\n"); + cout << "\nProblem: main GPT header's last usable LBA pointer (" << mainHeader.lastUsableLBA + << ") doesn't\nmatch the backup GPT header's last usable LBA pointer (" + << secondHeader.lastUsableLBA << ")\n" + << "The 'e' option on the experts' menu can probably fix this problem.\n"; } // if if ((mainHeader.diskGUID.data1 != secondHeader.diskGUID.data1) || (mainHeader.diskGUID.data2 != secondHeader.diskGUID.data2)) { problems++; - printf("\nProblem: main header's disk GUID (%s) doesn't\n", - GUIDToStr(mainHeader.diskGUID, tempStr)); - printf("match the backup GPT header's disk GUID (%s)\n", - GUIDToStr(secondHeader.diskGUID, tempStr)); - printf("You should use the 'b' or 'd' option on the recovery & transformation menu to\n" - "select one or the other header.\n"); + cout << "\nProblem: main header's disk GUID (" << GUIDToStr(mainHeader.diskGUID) + << ") doesn't\nmatch the backup GPT header's disk GUID (" + << GUIDToStr(secondHeader.diskGUID) << ")\n" + << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" + << "select one or the other header.\n"; } // if if (mainHeader.numParts != secondHeader.numParts) { problems++; - printf("\nProblem: main GPT header's number of partitions (%lu) doesn't\n" - "match the backup GPT header's number of partitions (%lu)\n", - (unsigned long) mainHeader.numParts, - (unsigned long) secondHeader.numParts); - printf("Resizing the partition table ('s' on the experts' menu) may help.\n"); + cout << "\nProblem: main GPT header's number of partitions (" << mainHeader.numParts + << ") doesn't\nmatch the backup GPT header's number of partitions (" + << secondHeader.numParts << ")\n" + << "Resizing the partition table ('s' on the experts' menu) may help.\n"; } // if if (mainHeader.sizeOfPartitionEntries != secondHeader.sizeOfPartitionEntries) { problems++; - printf("\nProblem: main GPT header's size of partition entries (%lu) doesn't\n" - "match the backup GPT header's size of partition entries (%lu)\n", - (unsigned long) mainHeader.sizeOfPartitionEntries, - (unsigned long) secondHeader.sizeOfPartitionEntries); - printf("You should use the 'b' or 'd' option on the recovery & transformation menu to\n" - "select one or the other header.\n"); + cout << "\nProblem: main GPT header's size of partition entries (" + << mainHeader.sizeOfPartitionEntries << ") doesn't\n" + << "match the backup GPT header's size of partition entries (" + << secondHeader.sizeOfPartitionEntries << ")\n" + << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n" + << "select one or the other header.\n"; } // if // Now check for a few other miscellaneous problems... // Check that the disk size will hold the data... if (mainHeader.backupLBA > diskSize) { problems++; - printf("\nProblem: Disk is too small to hold all the data!\n"); - printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n", - (unsigned long long) diskSize, - (unsigned long long) mainHeader.backupLBA); - printf("The 'e' option on the experts' menu may fix this problem.\n"); + cout << "\nProblem: Disk is too small to hold all the data!\n" + << "(Disk size is " << diskSize << " sectors, needs to be " + << mainHeader.backupLBA << " sectors.)\n" + << "The 'e' option on the experts' menu may fix this problem.\n"; } // if // Check for overlapping partitions.... @@ -227,9 +221,9 @@ int GPTData::Verify(void) { // Format and similar disks).... for (i = 0; i < mainHeader.numParts; i++) { if ((partitions[i].GetFirstLBA() % sectorAlignment) != 0) { - printf("\nCaution: Partition %d doesn't begin on a %d-sector boundary. This may\n" - "result in degraded performance on some modern (2010 and later) hard disks.\n", - i + 1, sectorAlignment); + cout << "\nCaution: Partition " << i + 1 << " doesn't begin on a " + << sectorAlignment << "-sector boundary. This may\nresult " + << "in degraded performance on some modern (2009 and later) hard disks.\n"; } // if } // for @@ -237,14 +231,15 @@ int GPTData::Verify(void) { // problems could affect the results if (problems == 0) { totalFree = FindFreeBlocks(&numSegments, &largestSegment); - BytesToSI(totalFree * (uint64_t) blockSize, siTotal); - BytesToSI(largestSegment * (uint64_t) blockSize, siLargest); - printf("No problems found. %llu free sectors ", (unsigned long long) totalFree); - printf("(%s) available in %u\n", siTotal, numSegments); - printf("segments, the largest of which is %llu sectors ", (unsigned long long) largestSegment); - printf("(%s) in size\n", siLargest); + strcpy(siTotal, BytesToSI(totalFree * (uint64_t) blockSize).c_str()); + strcpy(siLargest, BytesToSI(largestSegment * (uint64_t) blockSize).c_str()); + cout << "No problems found. " << totalFree << " free sectors (" + << BytesToSI(totalFree * (uint64_t) blockSize) << ") available in " + << numSegments << "\nsegments, the largest of which is " + << largestSegment << " (" << BytesToSI(largestSegment * (uint64_t) blockSize) + << ") in size\n"; } else { - printf("\nIdentified %d problems!\n", problems); + cout << "\nIdentified %d problems!\n", problems; } // if/else return (problems); @@ -275,27 +270,25 @@ int GPTData::CheckGPTSize(void) { if (diskSize != 0) { if (mainHeader.firstUsableLBA > firstUsedBlock) { overlap = mainHeader.firstUsableLBA - firstUsedBlock; - printf("Warning! Main partition table overlaps the first partition by %lu blocks!\n", - (unsigned long) overlap); + cout << "Warning! Main partition table overlaps the first partition by " + << overlap << " blocks!\n"; if (firstUsedBlock > 2) { - printf("Try reducing the partition table size by %lu entries.\n", - (unsigned long) (overlap * 4)); - printf("(Use the 's' item on the experts' menu.)\n"); + cout << "Try reducing the partition table size by " << overlap * 4 + << " entries.\n(Use the 's' item on the experts' menu.)\n"; } else { - printf("You will need to delete this partition or resize it in another utility.\n"); + cout << "You will need to delete this partition or resize it in another utility.\n"; } // if/else numProbs++; } // Problem at start of disk if (mainHeader.lastUsableLBA < lastUsedBlock) { overlap = lastUsedBlock - mainHeader.lastUsableLBA; - printf("Warning! Secondary partition table overlaps the last partition by %lu blocks!\n", - (unsigned long) overlap); + cout << "Warning! Secondary partition table overlaps the last partition by " + << overlap << " blocks!\n"; if (lastUsedBlock > (diskSize - 2)) { - printf("You will need to delete this partition or resize it in another utility.\n"); + cout << "You will need to delete this partition or resize it in another utility.\n"; } else { - printf("Try reducing the partition table size by %lu entries.\n", - (unsigned long) (overlap * 4)); - printf("(Use the 's' item on the experts' menu.)\n"); + cout << "Try reducing the partition table size by " << overlap * 4 + << " entries.\n(Use the 's' item on the experts' menu.)\n"; } // if/else numProbs++; } // Problem at end of disk @@ -310,24 +303,31 @@ int GPTData::CheckGPTSize(void) { int GPTData::CheckHeaderValidity(void) { int valid = 3; + cout.setf(ios::uppercase); + cout.fill('0'); + + // Note: failed GPT signature checks produce no error message because + // a message is displayed in the ReversePartitionBytes() function if (mainHeader.signature != GPT_SIGNATURE) { valid -= 1; -// printf("Main GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n", -// (unsigned long long) mainHeader.signature, (unsigned long long) GPT_SIGNATURE); } else if ((mainHeader.revision != 0x00010000) && valid) { valid -= 1; - printf("Unsupported GPT version in main header; read 0x%08lX, should be\n0x%08lX\n", - (unsigned long) mainHeader.revision, (unsigned long) UINT32_C(0x00010000)); + cout << "Unsupported GPT version in main header; read 0x"; + cout.width(8); + cout << hex << mainHeader.revision << ", should be\n0x"; + cout.width(8); + cout << UINT32_C(0x00010000) << dec << "\n"; } // if/else/if if (secondHeader.signature != GPT_SIGNATURE) { valid -= 2; -// printf("Secondary GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n", -// (unsigned long long) secondHeader.signature, (unsigned long long) GPT_SIGNATURE); } else if ((secondHeader.revision != 0x00010000) && valid) { valid -= 2; - printf("Unsupported GPT version in backup header; read 0x%08lX, should be\n0x%08lX\n", - (unsigned long) mainHeader.revision, (unsigned long) UINT32_C(0x00010000)); + cout << "Unsupported GPT version in backup header; read 0x"; + cout.width(8); + cout << hex << secondHeader.revision << ", should be\n0x"; + cout.width(8); + cout << UINT32_C(0x00010000) << dec << "\n"; } // if/else/if // If MBR bad, check for an Apple disk signature @@ -336,8 +336,9 @@ int GPTData::CheckHeaderValidity(void) { (mainHeader.signature << 32) == APM_SIGNATURE2)) { apmFound = 1; // Will display warning message later } // if + cout.fill(' '); - return valid; + return valid; } // GPTData::CheckHeaderValidity() // Check the header CRC to see if it's OK... @@ -474,10 +475,15 @@ int GPTData::FindHybridMismatches(void) { } while ((!found) && (j < mainHeader.numParts)); if (!found) { numFound++; - printf("\nWarning! Mismatched GPT and MBR partitions! MBR partition " - "%d, of type 0x%02X,\nhas no corresponding GPT partition! " - "You may continue, but this condition\nmight cause data loss" - " in the future!\a\n", i + 1, protectiveMBR.GetType(i)); + cout << "\nWarning! Mismatched GPT and MBR partition! MBR partition " + << i + 1 << ", of type 0x"; + cout.fill('0'); + cout.setf(ios::uppercase); + cout.width(2); + cout << hex << (int) protectiveMBR.GetType(i) << ",\n" + << "has no corresponding GPT partition! You may continue, but this condition\n" + << "might cause data loss in the future!\a\n" << dec; + cout.fill(' '); } // if } // if } // for @@ -493,13 +499,11 @@ int GPTData::FindOverlaps(void) { for (j = 0; j < i; j++) { if (partitions[i].DoTheyOverlap(&partitions[j])) { problems++; - printf("\nProblem: partitions %d and %d overlap:\n", i + 1, j + 1); - printf(" Partition %d: %llu to %llu\n", i, - (unsigned long long) partitions[i].GetFirstLBA(), - (unsigned long long) partitions[i].GetLastLBA()); - printf(" Partition %d: %llu to %llu\n", j, - (unsigned long long) partitions[j].GetFirstLBA(), - (unsigned long long) partitions[j].GetLastLBA()); + cout << "\nProblem: partitions " << i + 1 << " and " << j + 1 << " overlap:\n"; + cout << " Partition " << i + 1 << ": " << partitions[i].GetFirstLBA() + << " to " << partitions[i].GetLastLBA() << "\n"; + cout << " Partition " << j + 1 << ": " << partitions[j].GetFirstLBA() + << " to " << partitions[j].GetLastLBA() << "\n"; } // if } // for j... } // for i... @@ -527,44 +531,44 @@ void GPTData::PartitionScan(void) { ForceLoadGPTData(); if (!beQuiet) { - printf("Partition table scan:\n"); + cout << "Partition table scan:\n"; protectiveMBR.ShowState(); bsdDisklabel.ShowState(); ShowAPMState(); // Show whether there's an Apple Partition Map present ShowGPTState(); // Show GPT status - printf("\n"); + cout << "\n"; } // if if (apmFound) { - printf("\n*******************************************************************\n"); - printf("This disk appears to contain an Apple-format (APM) partition table!\n"); + cout << "\n*******************************************************************\n" + << "This disk appears to contain an Apple-format (APM) partition table!\n"; if (!justLooking) { - printf("It will be destroyed if you continue!\n"); + cout << "It will be destroyed if you continue!\n"; } // if - printf("*******************************************************************\n\n\a"); + cout << "*******************************************************************\n\n\a"; } // if } // GPTData::PartitionScan() // Read GPT data from a disk. -int GPTData::LoadPartitions(char* deviceFilename) { - int fd, err; +int GPTData::LoadPartitions(string deviceFilename) { + int err; int allOK = 1, i; uint64_t firstBlock, lastBlock; BSDData bsdDisklabel; + MBRValidity mbrState; // First, do a test to see if writing will be possible later.... - fd = myDisk.OpenForWrite(deviceFilename); - if ((fd == -1) && (!justLooking)) { - printf("\aNOTE: Write test failed with error number %d. It will be " - "impossible to save\nchanges to this disk's partition table!\n", - errno); + err = myDisk.OpenForWrite(deviceFilename); + if ((err == 0) && (!justLooking)) { + cout << "\aNOTE: Write test failed with error number " << errno + << ". It will be impossible to save\nchanges to this disk's partition table!\n"; #ifdef __FreeBSD__ - printf("You may be able to enable writes by exiting this program, typing\n" - "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n" - "program.\n"); + cout << "You may be able to enable writes by exiting this program, typing\n" + << "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n" + << "program.\n"; #endif - printf("\n"); - justLooking = 1; + cout << "\n"; +// justLooking = 1; } // if myDisk.Close(); @@ -574,7 +578,7 @@ int GPTData::LoadPartitions(char* deviceFilename) { diskSize = myDisk.DiskSize(&err); blockSize = (uint32_t) myDisk.GetBlockSize(); sectorAlignment = myDisk.FindAlignment(); - strcpy(device, deviceFilename); + device = deviceFilename; PartitionScan(); // Check for partition types, load GPT, & print summary whichWasUsed = UseWhichPartitions(); @@ -590,6 +594,9 @@ int GPTData::LoadPartitions(char* deviceFilename) { XFormDisklabel(&bsdDisklabel, 0); break; case use_gpt: + mbrState = protectiveMBR.GetValidity(); + if ((mbrState == invalid) || (mbrState == mbr)) + protectiveMBR.MakeProtectiveMBR(); break; case use_new: ClearGPTData(); @@ -597,7 +604,7 @@ int GPTData::LoadPartitions(char* deviceFilename) { break; case use_abort: allOK = 0; - printf("Aborting because of invalid partition data!\n"); + cerr << "Aborting because of invalid partition data!\n"; break; } // switch @@ -616,10 +623,10 @@ int GPTData::LoadPartitions(char* deviceFilename) { } // if } else { allOK = 0; - fprintf(stderr, "Problem opening %s for reading! Error is %d\n", - deviceFilename, errno); + cerr << "Problem opening " << deviceFilename << " 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 } // if/else return (allOK); @@ -630,13 +637,13 @@ int GPTData::LoadPartitions(char* deviceFilename) { int GPTData::ForceLoadGPTData(void) { int allOK = 1, validHeaders; off_t seekTo; - char* storage; + uint8_t* storage; uint32_t newCRC, sizeOfParts; // Seek to and read the main GPT header if (myDisk.Seek(1)) { if (myDisk.Read(&mainHeader, 512) != 512) { // read main GPT header - fprintf(stderr, "Warning! Error %d reading main GPT header!\n", errno); + cerr << "Warning! Error " << errno << " reading main GPT header!\n"; } // if read not OK } else allOK = 0; // if/else seek OK mainCrcOk = CheckHeaderCRC(&mainHeader); @@ -653,10 +660,10 @@ int GPTData::ForceLoadGPTData(void) { seekTo = mainHeader.backupLBA; } else { seekTo = diskSize - UINT64_C(1); - printf("Warning! Disk size is smaller than the main header indicates! Loading\n" - "secondary header from the last sector of the disk! You should use 'v' to\n" - "verify disk integrity, and perhaps options on the experts' menu to repair\n" - "the disk.\n"); + cout << "Warning! Disk size is smaller than the main header indicates! Loading\n" + << "secondary header from the last sector of the disk! You should use 'v' to\n" + << "verify disk integrity, and perhaps options on the experts' menu to repair\n" + << "the disk.\n"; } // else } else { seekTo = diskSize - UINT64_C(1); @@ -664,7 +671,7 @@ int GPTData::ForceLoadGPTData(void) { if (myDisk.Seek(seekTo)) { if (myDisk.Read(&secondHeader, 512) != 512) { // read secondary GPT header - fprintf(stderr, "Warning! Error %d reading secondary GPT header!\n", errno); + cerr << "Warning! Error " << errno << " reading secondary GPT header!\n"; } // if secondCrcOk = CheckHeaderCRC(&secondHeader); if (IsLittleEndian() == 0) // big-endian system; adjust header byte order.... @@ -672,8 +679,8 @@ int GPTData::ForceLoadGPTData(void) { } else { allOK = 0; state = gpt_invalid; - fprintf(stderr, "Unable to seek to secondary GPT header at sector %llu!\n", - (unsigned long long) (diskSize - (UINT64_C(1)))); + cerr << "Unable to seek to secondary GPT header at sector " + << (diskSize - (UINT64_C(1))) << "!\n"; } // if/else lseek // Return valid headers code: 0 = both headers bad; 1 = main header @@ -692,14 +699,14 @@ int GPTData::ForceLoadGPTData(void) { // of the two headers is corrupt. If so, use the one that seems to // be in better shape to regenerate the bad one if (validHeaders == 1) { // valid main header, invalid backup header - fprintf(stderr, "\aCaution: invalid backup GPT header, but valid main header; regenerating\n" - "backup header from main header.\n\n"); + cerr << "\aCaution: invalid backup GPT header, but valid main header; regenerating\n" + << "backup header from main header.\n\n"; RebuildSecondHeader(); state = gpt_corrupt; secondCrcOk = mainCrcOk; // Since regenerated, use CRC validity of main } else if (validHeaders == 2) { // valid backup header, invalid main header - fprintf(stderr, "\aCaution: invalid main GPT header, but valid backup; regenerating main header\n" - "from backup!\n\n"); + cerr << "\aCaution: invalid main GPT header, but valid backup; regenerating main header\n" + << "from backup!\n\n"; RebuildMainHeader(); state = gpt_corrupt; mainCrcOk = secondCrcOk; // Since copied, use CRC validity of backup @@ -714,11 +721,11 @@ int GPTData::ForceLoadGPTData(void) { } else { // bad main header CRC and backup header CRC is OK state = gpt_corrupt; if (LoadSecondTableAsMain()) { - fprintf(stderr, "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n"); + cerr << "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n"; } else { // backup table bad, bad main header CRC, but try main table in desperation.... if (LoadMainTable() == 0) { allOK = 0; - fprintf(stderr, "\a\aWarning! Unable to load either main or backup partition table!\n"); + cerr << "\a\aWarning! Unable to load either main or backup partition table!\n"; } // if } // if/else (LoadSecondTableAsMain()) } // if/else (load partition table) @@ -729,9 +736,9 @@ int GPTData::ForceLoadGPTData(void) { seekTo = secondHeader.partitionEntriesLBA; if ((myDisk.Seek(seekTo)) && (secondCrcOk)) { sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries; - storage = (char*) malloc(sizeOfParts); + storage = (uint8_t*) malloc(sizeOfParts); if (myDisk.Read(storage, sizeOfParts) != sizeOfParts) { - fprintf(stderr, "Warning! Error %d reading backup partition table!\n", errno); + cerr << "Warning! Error " << errno << " reading backup partition table!\n"; } // if newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts); free(storage); @@ -742,14 +749,14 @@ int GPTData::ForceLoadGPTData(void) { if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) { state = gpt_corrupt; allOK = allOK && LoadSecondTableAsMain(); - fprintf(stderr, "\aWarning! Main partition table CRC mismatch! Loaded backup " - "partition table\ninstead of main partition table!\n\n"); + cerr << "\aWarning! Main partition table CRC mismatch! Loaded backup " + << "partition table\ninstead of main partition table!\n\n"; } // if // Check for valid CRCs and warn if there are problems if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) || (secondPartsCrcOk == 0)) { - printf("Warning! One or more CRCs don't match. You should repair the disk!\n\n"); + cerr << "Warning! One or more CRCs don't match. You should repair the disk!\n\n"; state = gpt_corrupt; } // if } else { @@ -776,7 +783,7 @@ int GPTData::LoadMainTable(void) { retval = 0; sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries; if (myDisk.Read(partitions, sizeOfParts) != sizeOfParts) { - fprintf(stderr, "Warning! Error %d when loading the main partition table!\n", errno); + cerr << "Warning! Error " << errno << " when loading the main partition table!\n"; retval = 0; } // if newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); @@ -803,7 +810,7 @@ int GPTData::LoadSecondTableAsMain(void) { SetGPTSize(secondHeader.numParts); sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries; if (myDisk.Read(partitions, sizeOfParts) != sizeOfParts) { - fprintf(stderr, "Warning! Read error %d! Misbehavior now likely!\n", errno); + cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n"; retval = 0; } // if newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); @@ -812,13 +819,14 @@ int GPTData::LoadSecondTableAsMain(void) { if (IsLittleEndian() == 0) ReversePartitionBytes(); if (!secondPartsCrcOk) { - printf("Error! After loading backup partitions, the CRC still doesn't check out!\n"); + cout << "Caution! After loading backup partitions, the CRC still doesn't check out!\n"; } // if } else { - printf("Error! Couldn't seek to backup partition table!\n", retval); + cerr << "Error! Couldn't seek to backup partition table!\n"; } // if/else } else { - printf("Error! Couldn't open device %s when recovering backup partition table!\n", device); + cerr << "Error! Couldn't open device " << device + << " when recovering backup partition table!\n"; retval = 0; } // if/else return retval; @@ -833,15 +841,15 @@ int GPTData::SaveGPTData(int quiet) { uint32_t numParts; off_t offset; - if (strlen(device) == 0) { - printf("Device not defined.\n"); + if (device == "") { + cerr << "Device not defined.\n"; } // if // First do some final sanity checks.... // This test should only fail on read-only disks.... if (justLooking) { - printf("The justLooking flag is set. This probably means you can't write to the disk.\n"); + cout << "The justLooking flag is set. This probably means you can't write to the disk.\n"; allOK = 0; } // if @@ -853,29 +861,28 @@ int GPTData::SaveGPTData(int quiet) { // Check that disk is really big enough to handle this... if (mainHeader.backupLBA > diskSize) { - fprintf(stderr, "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n" - "problem (or it might not). Aborting!\n"); - printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n", - (unsigned long long) diskSize, (unsigned long long) mainHeader.backupLBA); + cerr << "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n" + << "problem (or it might not). Aborting!\n(Disk size is " + << diskSize << " sectors, needs to be " << mainHeader.backupLBA << " sectors.)\n"; allOK = 0; } // if // Check that second header is properly placed. Warn and ask if this should // be corrected if the test fails.... if ((mainHeader.backupLBA < (diskSize - UINT64_C(1))) && (quiet == 0)) { - printf("Warning! Secondary header is placed too early on the disk! Do you want to\n" - "correct this problem? "); + cout << "Warning! Secondary header is placed too early on the disk! Do you want to\n" + << "correct this problem? "; if (GetYN() == 'Y') { MoveSecondHeaderToEnd(); - printf("Have moved second header and partition table to correct location.\n"); + cout << "Have moved second header and partition table to correct location.\n"; } else { - printf("Have not corrected the problem. Strange problems may occur in the future!\n"); + cout << "Have not corrected the problem. Strange problems may occur in the future!\n"; } // if correction requested } // if // Check for overlapping partitions.... if (FindOverlaps() > 0) { allOK = 0; - fprintf(stderr, "Aborting write operation!\n"); + cerr << "Aborting write operation!\n"; } // if // Check for mismatched MBR and GPT data, but let it pass if found @@ -896,12 +903,11 @@ int GPTData::SaveGPTData(int quiet) { RecomputeCRCs(); if ((allOK) && (!quiet)) { - printf("\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"); - printf("MBR PARTITIONS!!\n\n"); - printf("Do you want to proceed, possibly destroying your data? "); + cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n" + << "PARTITIONS!!\n\nDo you want to proceed, possibly destroying your data? "; answer = GetYN(); if (answer == 'Y') { - printf("OK; writing new GUID partition table (GPT).\n"); + cout << "OK; writing new GUID partition table (GPT).\n"; } else { allOK = 0; } // if/else @@ -933,8 +939,8 @@ int GPTData::SaveGPTData(int quiet) { offset = (off_t) secondTable; if (myDisk.Seek(offset) != 1) { allOK = 0; - printf("Unable to seek to end of disk! Perhaps the 'e' option on the experts' menu\n" - "will resolve this problem.\n"); + cerr << "Unable to seek to end of disk! Perhaps the 'e' option on the experts' menu\n" + << "will resolve this problem.\n"; } // if } // if @@ -959,20 +965,20 @@ int GPTData::SaveGPTData(int quiet) { } // if if (allOK) { // writes completed OK - printf("The operation has completed successfully.\n"); + cout << "The operation has completed successfully.\n"; } else { - printf("Warning! An error was reported when writing the partition table! This error\n"); - printf("MIGHT be harmless, but you may have trashed the disk! Use parted and, if\n"); - printf("necessary, restore your original partition table.\n"); + cerr << "Warning! An error was reported when writing the partition table! This error\n" + << "MIGHT be harmless, but you may have trashed the disk! Use parted and, if\n" + << "necessary, restore your original partition table.\n"; } // if/else myDisk.Close(); } else { - fprintf(stderr, "Unable to open device %s for writing! Errno is %d! Aborting write!\n", - device, errno); + cerr << "Unable to open device " << device << " for writing! Errno is " + << errno << "! Aborting write!\n"; allOK = 0; } // if/else } else { - printf("Aborting write of new partition table.\n"); + cout << "Aborting write of new partition table.\n"; } // if if (IsLittleEndian() == 0) { @@ -992,7 +998,7 @@ int GPTData::SaveGPTData(int quiet) { // the main GPT header, the backup GPT header, and the main partition // table; it discards the backup partition table, since it should be // identical to the main partition table on healthy disks. -int GPTData::SaveGPTBackup(char* filename) { +int GPTData::SaveGPTBackup(string filename) { int fd, allOK = 1; uint32_t numParts; DiskIO backupFile; @@ -1036,10 +1042,10 @@ int GPTData::SaveGPTBackup(char* filename) { } // if if (allOK) { // writes completed OK - printf("The operation has completed successfully.\n"); + cout << "The operation has completed successfully.\n"; } else { - printf("Warning! An error was reported when writing the backup file.\n"); - printf("It may not be usable!\n"); + cerr << "Warning! An error was reported when writing the backup file.\n" + << "It may not be usable!\n"; } // if/else backupFile.Close(); @@ -1050,7 +1056,7 @@ int GPTData::SaveGPTBackup(char* filename) { ReversePartitionBytes(); } // if } else { - fprintf(stderr, "Unable to open file %s for writing! Aborting!\n", filename); + cerr << "Unable to open file " << filename << " for writing! Aborting!\n"; allOK = 0; } // if/else return allOK; @@ -1060,7 +1066,7 @@ int GPTData::SaveGPTBackup(char* filename) { // does minimal error checking. It returns 1 if it completed successfully, // 0 if there was a problem. In the latter case, it creates a new empty // set of partitions. -int GPTData::LoadGPTBackup(char* filename) { +int GPTData::LoadGPTBackup(string filename) { int fd, allOK = 1, val; uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC; int littleEndian = 1; @@ -1077,7 +1083,7 @@ int GPTData::LoadGPTBackup(char* filename) { // Load the main GPT header, check its vaility, and set the GPT // size based on the data if (backupFile.Read(&mainHeader, 512) != 512) { - fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno); + cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; } // if mainCrcOk = CheckHeaderCRC(&mainHeader); @@ -1089,7 +1095,7 @@ int GPTData::LoadGPTBackup(char* filename) { // Load the backup GPT header in much the same way as the main // GPT header.... if (backupFile.Read(&secondHeader, 512) != 512) { - fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno); + cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; } // if secondCrcOk = CheckHeaderCRC(&secondHeader); @@ -1116,8 +1122,8 @@ int GPTData::LoadGPTBackup(char* filename) { // If current disk size doesn't match that of backup.... if (secondHeader.currentLBA != diskSize - UINT64_C(1)) { - printf("Warning! Current disk size doesn't match that of the backup!\n" - "Adjusting sizes to match, but subsequent problems are possible!\n"); + cout << "Warning! Current disk size doesn't match that of the backup!\n" + << "Adjusting sizes to match, but subsequent problems are possible!\n"; MoveSecondHeaderToEnd(); } // if @@ -1125,7 +1131,7 @@ int GPTData::LoadGPTBackup(char* filename) { // matches the stored value sizeOfParts = numParts * sizeOfEntries; if (backupFile.Read(partitions, sizeOfParts) != sizeOfParts) { - fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno); + cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n"; } // if newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); @@ -1141,7 +1147,7 @@ int GPTData::LoadGPTBackup(char* filename) { } // if/else } else { allOK = 0; - fprintf(stderr, "Unable to open file %s for reading! Aborting!\n", filename); + cerr << "Unable to open file " << filename << " for reading! Aborting!\n"; } // if/else // Something went badly wrong, so blank out partitions @@ -1155,25 +1161,25 @@ int GPTData::LoadGPTBackup(char* filename) { // Tell user whether Apple Partition Map (APM) was discovered.... void GPTData::ShowAPMState(void) { if (apmFound) - printf(" APM: present\n"); + cout << " APM: present\n"; else - printf(" APM: not present\n"); + cout << " APM: not present\n"; } // GPTData::ShowAPMState() // Tell user about the state of the GPT data.... void GPTData::ShowGPTState(void) { switch (state) { case gpt_invalid: - printf(" GPT: not present\n"); + cout << " GPT: not present\n"; break; case gpt_valid: - printf(" GPT: present\n"); + cout << " GPT: present\n"; break; case gpt_corrupt: - printf(" GPT: damaged\n"); + cout << " GPT: damaged\n"; break; default: - printf("\a GPT: unknown -- bug!\n"); + cout << "\a GPT: unknown -- bug!\n"; break; } // switch } // GPTData::ShowGPTState() @@ -1181,24 +1187,20 @@ void GPTData::ShowGPTState(void) { // Display the basic GPT data void GPTData::DisplayGPTData(void) { int i; - char sizeInSI[255]; // String to hold size of disk in SI units - char tempStr[255]; +// char tempStr[255]; uint64_t temp, totalFree; - BytesToSI(diskSize * blockSize, sizeInSI); - printf("Disk %s: %llu sectors, ", device, - (unsigned long long) diskSize); - printf("%s\n", sizeInSI); - printf("Logical sector size: %d bytes\n", blockSize); - printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr)); - printf("Partition table holds up to %lu entries\n", (unsigned long) mainHeader.numParts); - printf("First usable sector is %llu, last usable sector is %llu\n", - (unsigned long long) mainHeader.firstUsableLBA, - (unsigned long long) mainHeader.lastUsableLBA); + cout << "Disk " << device << ": " << diskSize << " sectors, " + << BytesToSI(diskSize * blockSize) << "\n"; + cout << "Logical sector size: " << blockSize << " bytes\n"; + cout << "Disk identifier (GUID): " << GUIDToStr(mainHeader.diskGUID) << "\n"; + cout << "Partition table holds up to " << mainHeader.numParts << " entries\n"; + cout << "First usable sector is " << mainHeader.firstUsableLBA + << ", last usable sector is " << mainHeader.lastUsableLBA << "\n"; totalFree = FindFreeBlocks(&i, &temp); - printf("Total free space is %llu sectors ", (unsigned long long) totalFree); - printf("(%s)\n", BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI)); - printf("\nNumber Start (sector) End (sector) Size Code Name\n"); + cout << "Total free space is " << totalFree << " sectors (" + << BytesToSI(totalFree * (uint64_t) blockSize) << ")\n"; + cout << "\nNumber Start (sector) End (sector) Size Code Name\n"; for (i = 0; i < mainHeader.numParts; i++) { partitions[i].ShowSummary(i, blockSize); } // for @@ -1214,7 +1216,7 @@ void GPTData::ShowDetails(void) { partNum = GetPartNum(); ShowPartDetails(partNum); } else { - printf("No partitions\n"); + cout << "No partitions\n"; } // if/else } // GPTData::ShowDetails() @@ -1223,7 +1225,7 @@ void GPTData::ShowPartDetails(uint32_t partNum) { if (partitions[partNum].GetFirstLBA() != 0) { partitions[partNum].ShowDetails(blockSize); } else { - printf("Partition #%d does not exist.", (int) (partNum + 1)); + cout << "Partition #" << partNum + 1 << " does not exist."; } // if } // GPTData::ShowPartDetails() @@ -1253,8 +1255,7 @@ void GPTData::ResizePartitionTable(void) { char prompt[255]; uint32_t curLow, curHigh; - printf("Current partition table size is %lu.\n", - (unsigned long) mainHeader.numParts); + cout << "Current partition table size is " << mainHeader.numParts << ".\n"; GetPartRange(&curLow, &curHigh); curHigh++; // since GetPartRange() returns numbers starting from 0... // There's no point in having fewer than four partitions.... @@ -1264,10 +1265,10 @@ void GPTData::ResizePartitionTable(void) { (int) NUM_GPT_ENTRIES); newSize = GetNumber(4, 65535, 128, prompt); if (newSize < 128) { - printf("Caution: The partition table size should officially be 16KB or larger,\n" - "which works out to 128 entries. In practice, smaller tables seem to\n" - "work with most OSes, but this practice is risky. I'm proceeding with\n" - "the resize, but you may want to reconsider this action and undo it.\n\n"); + cout << "Caution: The partition table size should officially be 16KB or larger,\n" + << "which works out to 128 entries. In practice, smaller tables seem to\n" + << "work with most OSes, but this practice is risky. I'm proceeding with\n" + << "the resize, but you may want to reconsider this action and undo it.\n\n"; } // if SetGPTSize(newSize); } // GPTData::ResizePartitionTable() @@ -1295,7 +1296,7 @@ void GPTData::CreatePartition(void) { partNum = GetNumber(firstFreePart + 1, mainHeader.numParts, firstFreePart + 1, prompt) - 1; if (partitions[partNum].GetFirstLBA() != 0) - printf("partition %d is in use.\n", partNum + 1); + cout << "partition " << partNum + 1 << " is in use.\n"; } while (partitions[partNum].GetFirstLBA() != 0); // Get first block for new partition... @@ -1320,9 +1321,9 @@ void GPTData::CreatePartition(void) { firstFreePart = CreatePartition(partNum, firstBlock, lastBlock); partitions[partNum].ChangeType(); - partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType().c_str()); + partitions[partNum].SetName(partitions[partNum].GetNameType()); } else { - printf("No free sectors available\n"); + cout << "No free sectors available\n"; } // if/else } // GPTData::CreatePartition() @@ -1337,7 +1338,7 @@ void GPTData::DeletePartition(void) { partNum = GetNumber(low + 1, high + 1, low, prompt); DeletePartition(partNum - 1); } else { - printf("No partitions\n"); + cout << "No partitions\n"; } // if/else } // GPTData::DeletePartition() @@ -1351,7 +1352,7 @@ void GPTData::ChangePartType(void) { partNum = GetPartNum(); partitions[partNum].ChangeType(); } else { - printf("No partitions\n"); + cout << "No partitions\n"; } // if/else } // GPTData::ChangePartType() @@ -1374,52 +1375,45 @@ void GPTData::SetAttributes(uint32_t partNum) { // MBR. int GPTData::DestroyGPT(int prompt) { int fd, i, sum, tableSize; - char blankSector[512], goOn = 'Y', blank = 'N'; - char* emptyTable; + uint8_t blankSector[512], goOn = 'Y', blank = 'N'; + uint8_t* emptyTable; for (i = 0; i < 512; i++) { - blankSector[i] = '\0'; + blankSector[i] = 0; } // for if (((apmFound) || (bsdFound)) && (prompt > 0)) { - printf("WARNING: APM or BSD disklabel structures detected! This operation could\n" - "damage any APM or BSD partitions on this disk!\n"); + cout << "WARNING: APM or BSD disklabel structures detected! This operation could\n" + << "damage any APM or BSD partitions on this disk!\n"; } // if APM or BSD if (prompt > 0) { - printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device); + cout << "\a\aAbout to wipe out GPT on " << device << ". Proceed? "; goOn = GetYN(); } // if if (goOn == 'Y') { -/* OpenForWrite(device); -#ifdef __APPLE__ - // MacOS X requires a shared lock under some circumstances.... - if (fd < 0) { - fd = open(device, O_WRONLY|O_SHLOCK); - } // if -#endif */ if (myDisk.OpenForWrite(device)) { myDisk.Seek(mainHeader.currentLBA); // seek to GPT header if (myDisk.Write(blankSector, 512) != 512) { // blank it out - fprintf(stderr, "Warning! GPT main header not overwritten! Error is %d\n", errno); + cerr << "Warning! GPT main header not overwritten! Error is " << errno << "\n"; } // if myDisk.Seek(mainHeader.partitionEntriesLBA); // seek to partition table tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries; - emptyTable = (char*) malloc(tableSize); + emptyTable = (uint8_t*) malloc(tableSize); for (i = 0; i < tableSize; i++) - emptyTable[i] = (char) 0; + emptyTable[i] = 0; sum = myDisk.Write(emptyTable, tableSize); if (sum != tableSize) - fprintf(stderr, "Warning! GPT main partition table not overwritten! Error is %d\n", errno); + cerr << "Warning! GPT main partition table not overwritten! Error is " << errno << "\n"; myDisk.Seek(secondHeader.partitionEntriesLBA); // seek to partition table sum = myDisk.Write(emptyTable, tableSize); if (sum != tableSize) - fprintf(stderr, "Warning! GPT backup partition table not overwritten! Error is %d\n", errno); + cerr << "Warning! GPT backup partition table not overwritten! Error is " << errno << "\n"; myDisk.Seek(secondHeader.currentLBA); // seek to GPT header if (myDisk.Write(blankSector, 512) != 512) { // blank it out - fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno); + cerr << "Warning! GPT backup header not overwritten! Error is " << errno << "\n"; } // if if (prompt > 0) { - printf("Blank out MBR? "); + cout << "Blank out MBR? "; blank = GetYN(); } // if // Note on below: Touch the MBR only if the user wants it completely @@ -1430,18 +1424,18 @@ int GPTData::DestroyGPT(int prompt) { if ((blank == 'Y') || (prompt < 0)) { myDisk.Seek(0); if (myDisk.Write(blankSector, 512) != 512) { // blank it out - fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno); + cerr << "Warning! MBR not overwritten! Error is " << errno << "!\n"; } // if } else { - printf("MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n" - "with fdisk or another tool.\n"); + cout << "MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n" + << "with fdisk or another tool.\n"; } // if/else myDisk.DiskSync(); myDisk.Close(); - printf("GPT data structures destroyed! You may now partition the disk using fdisk or\n" - "other utilities. Program will now terminate.\n"); + cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n" + << "other utilities. Program will now terminate.\n"; } else { - printf("Problem opening %s for writing! Program will now terminate.\n", device); + cerr << "Problem opening " << device << " for writing! Program will now terminate.\n"; } // if/else (fd != -1) } // if (goOn == 'Y') return (goOn == 'Y'); @@ -1465,54 +1459,55 @@ WhichToUse GPTData::UseWhichPartitions(void) { mbrState = protectiveMBR.GetValidity(); if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) { - printf("\n***************************************************************\n" - "Found invalid GPT and valid MBR; converting MBR to GPT format.\n"); + cout << "\n***************************************************************\n" + << "Found invalid GPT and valid MBR; converting MBR to GPT format.\n"; if (!justLooking) { - printf("\aTHIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n" - "you don't want to convert your MBR partitions to GPT format!\n"); + cout << "\aTHIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n" + << "you don't want to convert your MBR partitions to GPT format!\n"; } // if - printf("***************************************************************\n\n"); + cout << "***************************************************************\n\n"; which = use_mbr; } // if if ((state == gpt_invalid) && bsdFound) { - printf("\n**********************************************************************\n" - "Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n" - "to GPT format."); + cout << "\n**********************************************************************\n" + << "Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n" + << "to GPT format."; if (!justLooking) { - printf("\a THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n" - "BSD partition will likely be unusable. Exit by typing 'q' if you don't\n" - "want to convert your BSD partitions to GPT format!"); + cout << "\a THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n" + << "BSD partition will likely be unusable. Exit by typing 'q' if you don't\n" + << "want to convert your BSD partitions to GPT format!"; } // if - printf("\n**********************************************************************\n\n"); + cout << "\n**********************************************************************\n\n"; which = use_bsd; } // if if ((state == gpt_valid) && (mbrState == gpt)) { which = use_gpt; if (!beQuiet) - printf("Found valid GPT with protective MBR; using GPT.\n"); + cout << "Found valid GPT with protective MBR; using GPT.\n"; } // if if ((state == gpt_valid) && (mbrState == hybrid)) { which = use_gpt; if (!beQuiet) - printf("Found valid GPT with hybrid MBR; using GPT.\n"); + cout << "Found valid GPT with hybrid MBR; using GPT.\n"; } // if if ((state == gpt_valid) && (mbrState == invalid)) { - printf("\aFound valid GPT with corrupt MBR; using GPT and will create new\nprotective MBR on save.\n"); + cout << "\aFound valid GPT with corrupt MBR; using GPT and will create new\n" + << "protective MBR on save.\n"; which = use_gpt; protectiveMBR.MakeProtectiveMBR(); } // if if ((state == gpt_valid) && (mbrState == mbr)) { if (!beQuiet) { - printf("Found valid MBR and GPT. Which do you want to use?\n"); - answer = GetNumber(1, 3, 2, (char*) " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); + cout << "Found valid MBR and GPT. Which do you want to use?\n"; + answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); if (answer == 1) { which = use_mbr; } else if (answer == 2) { which = use_gpt; protectiveMBR.MakeProtectiveMBR(); - printf("Using GPT and creating fresh protective MBR.\n"); + cout << "Using GPT and creating fresh protective MBR.\n"; } else which = use_new; } else which = use_abort; } // if @@ -1524,34 +1519,33 @@ WhichToUse GPTData::UseWhichPartitions(void) { which = use_abort; } else { if ((mbrState == mbr) || (mbrState == hybrid)) { - printf("Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n" - "GPT MAY permit recovery of GPT data.)\n"); - answer = GetNumber(1, 3, 2, (char*) " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); + cout << "Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n" + << "GPT MAY permit recovery of GPT data.)\n"; + answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: "); if (answer == 1) { which = use_mbr; - // protectiveMBR.MakeProtectiveMBR(); } else if (answer == 2) { which = use_gpt; } else which = use_new; } else if (mbrState == invalid) { - printf("Found invalid MBR and corrupt GPT. What do you want to do? (Using the\n" - "GPT MAY permit recovery of GPT data.)\n"); - answer = GetNumber(1, 2, 1, (char*) " 1 - GPT\n 2 - Create blank GPT\n\nYour answer: "); + cout << "Found invalid MBR and corrupt GPT. What do you want to do? (Using the\n" + << "GPT MAY permit recovery of GPT data.)\n"; + answer = GetNumber(1, 2, 1, " 1 - GPT\n 2 - Create blank GPT\n\nYour answer: "); if (answer == 1) { which = use_gpt; } else which = use_new; } else { // corrupt GPT, MBR indicates it's a GPT disk.... - printf("\a\a****************************************************************************\n" - "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n" - "verification and recovery are STRONGLY recommended.\n" - "****************************************************************************\n"); + cout << "\a\a****************************************************************************\n" + << "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n" + << "verification and recovery are STRONGLY recommended.\n" + << "****************************************************************************\n"; which = use_gpt; } // if/else/else } // else (beQuiet) } // if (corrupt GPT) if (which == use_new) - printf("Creating new GPT entries.\n"); + cout << "Creating new GPT entries.\n"; return which; } // UseWhichPartitions() @@ -1611,30 +1605,30 @@ int GPTData::XFormDisklabel(int i) { // Now see if the specified partition has a BSD type code.... hexCode = partitions[partNum].GetHexType(); if ((hexCode != 0xa500) && (hexCode != 0xa900)) { - printf("Specified partition doesn't have a disklabel partition type " - "code.\nContinue anyway?"); + cout << "Specified partition doesn't have a disklabel partition type " + << "code.\nContinue anyway? "; goOn = (GetYN() == 'Y'); } // if // If all is OK, read the disklabel and convert it. if (goOn) { - goOn = disklabel.ReadBSDData(device, partitions[partNum].GetFirstLBA(), + goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(), partitions[partNum].GetLastLBA()); if ((goOn) && (disklabel.IsDisklabel())) { numDone = XFormDisklabel(&disklabel, startPart); if (numDone == 1) - printf("Converted %d BSD partition.\n", numDone); + cout << "Converted " << numDone << " BSD partition.\n"; else - printf("Converted %d BSD partitions.\n", numDone); + cout << "Converted " << numDone << " BSD partitions.\n"; } else { - printf("Unable to convert partitions! Unrecognized BSD disklabel.\n"); + cout << "Unable to convert partitions! Unrecognized BSD disklabel.\n"; } // if/else } // if if (numDone > 0) { // converted partitions; delete carrier partitions[partNum].BlankPartition(); } // if } else { - printf("No partitions\n"); + cout << "No partitions\n"; } // if/else return numDone; } // GPTData::XFormDisklable(int i) @@ -1667,42 +1661,48 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) { char line[255]; char* junk; + cout.setf(ios::uppercase); + cout.fill('0'); + if ((mbrPart < 0) || (mbrPart > 3)) { - printf("MBR partition %d is out of range; omitting it.\n", mbrPart + 1); + cout << "MBR partition " << mbrPart + 1 << " is out of range; omitting it.\n"; allOK = 0; } // if if (gptPart >= mainHeader.numParts) { - printf("GPT partition %d is out of range; omitting it.\n", gptPart + 1); + cout << "GPT partition " << gptPart + 1 << " is out of range; omitting it.\n"; allOK = 0; } // if if (allOK && (partitions[gptPart].GetLastLBA() == UINT64_C(0))) { - printf("GPT partition %d is undefined; omitting it.\n", gptPart + 1); + cout << "GPT partition " << gptPart + 1 << " is undefined; omitting it.\n"; allOK = 0; } // if if (allOK && (partitions[gptPart].GetFirstLBA() <= UINT32_MAX) && (partitions[gptPart].GetLengthLBA() <= UINT32_MAX)) { if (partitions[gptPart].GetLastLBA() > UINT32_MAX) { - printf("Caution: Partition end point past 32-bit pointer boundary;" - " some OSes may\nreact strangely.\n"); + cout << "Caution: Partition end point past 32-bit pointer boundary;" + << " some OSes may\nreact strangely.\n"; } // if partition ends past 32-bit (usually 2TiB) boundary do { - printf("Enter an MBR hex code (default %02X): ", - typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256); + cout << "Enter an MBR hex code (default " << hex; + cout.width(2); + cout << typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256 << "): "; junk = fgets(line, 255, stdin); - sscanf(line, "%x", &typeCode); if (line[0] == '\n') typeCode = partitions[gptPart].GetHexType() / 256; + else + sscanf(line, "%x", &typeCode); } while ((typeCode <= 0) || (typeCode > 255)); - printf("Set the bootable flag? "); + cout << "Set the bootable flag? "; bootable = (GetYN() == 'Y'); length = partitions[gptPart].GetLengthLBA(); protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(), (uint32_t) length, typeCode, bootable); } else { // partition out of range - printf("Partition %d begins beyond the 32-bit pointer limit of MBR " - "partitions, or is\n too big; omitting it.\n", gptPart + 1); + cout << "Partition " << gptPart + 1 << " begins beyond the 32-bit pointer limit of MBR " + << "partitions, or is\n too big; omitting it.\n"; allOK = 0; } // if/else + cout.fill(' '); return allOK; } // GPTData::OnePartToMBR() @@ -1720,15 +1720,15 @@ int GPTData::XFormToMBR(void) { // Get the numbers of up to four partitions to add to the // hybrid MBR.... numParts = CountParts(); - printf("Counted %d partitions.\n", numParts); + cout << "Counted " << numParts << " partitions.\n"; // Prepare the MBR for conversion (empty it of existing partitions). protectiveMBR.EmptyMBR(0); protectiveMBR.SetDiskSize(diskSize); if (numParts > 4) { // Over four partitions; engage in triage - printf("Type from one to four GPT partition numbers, separated by spaces, to be\n" - "used in the MBR, in sequence: "); + cout << "Type from one to four GPT partition numbers, separated by spaces, to be\n" + << "used in the MBR, in sequence: "; junk = fgets(line, 255, stdin); numParts = sscanf(line, "%d %d %d %d", &partNums[0], &partNums[1], &partNums[2], &partNums[3]); @@ -1743,10 +1743,10 @@ int GPTData::XFormToMBR(void) { for (i = 0; i < numParts; i++) { j = partNums[i] - 1; - printf("\nCreating entry for partition #%d\n", j + 1); + cout << "\nCreating entry for partition #" << j + 1 << "\n"; numConverted += OnePartToMBR(j, i); } // for - printf("MBR writing returned %d\n", protectiveMBR.WriteMBRData(&myDisk)); + cout << "MBR writing returned " << protectiveMBR.WriteMBRData(&myDisk) << "\n"; return numConverted; } // GPTData::XFormToMBR() @@ -1760,14 +1760,14 @@ void GPTData::MakeHybrid(void) { char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe) char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table - printf("\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n" - "to use one, just hit the Enter key at the below prompt and your MBR\n" - "partition table will be untouched.\n\n\a"); + cout << "\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n" + << "to use one, just hit the Enter key at the below prompt and your MBR\n" + << "partition table will be untouched.\n\n\a"; // Now get the numbers of up to three partitions to add to the // hybrid MBR.... - printf("Type from one to three GPT partition numbers, separated by spaces, to be\n" - "added to the hybrid MBR, in sequence: "); + cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n" + << "added to the hybrid MBR, in sequence: "; junk = fgets(line, 255, stdin); numParts = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]); @@ -1776,13 +1776,13 @@ void GPTData::MakeHybrid(void) { // alone.... protectiveMBR.EmptyMBR(0); protectiveMBR.SetDiskSize(diskSize); - printf("Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? "); + cout << "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? "; eeFirst = GetYN(); } // if for (i = 0; i < numParts; i++) { j = partNums[i] - 1; - printf("\nCreating entry for partition #%d\n", j + 1); + cout << "\nCreating entry for partition #" << j + 1 << "\n"; if (eeFirst == 'Y') mbrNum = i + 1; else @@ -1811,13 +1811,13 @@ void GPTData::MakeHybrid(void) { for (i = 0; i < 4; i++) { if (protectiveMBR.GetType(i) == 0x00) { // unused entry.... if (fillItUp == 'M') { - printf("\nUnused partition space(s) found. Use one to protect more partitions? "); + cout << "\nUnused partition space(s) found. Use one to protect more partitions? "; fillItUp = GetYN(); typeCode = 0x00; // use this to flag a need to get type code } // if if (fillItUp == 'Y') { while ((typeCode <= 0) || (typeCode > 255)) { - printf("Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): "); + cout << "Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): "; // Comment on above: Mac OS treats disks with more than one // 0xEE MBR partition as MBR disks, not as GPT disks. junk = fgets(line, 255, stdin); @@ -1852,9 +1852,9 @@ int GPTData::SetGPTSize(uint32_t numEntries) { // that fills the allocated sectors i = blockSize / GPT_SIZE; if ((numEntries % i) != 0) { - printf("Adjusting GPT size from %lu ", (unsigned long) numEntries); + cout << "Adjusting GPT size from " << numEntries << " to "; numEntries = ((numEntries / i) + 1) * i; - printf("to %lu to fill the sector\n", (unsigned long) numEntries); + cout << numEntries << " to fill the sector\n"; } // if // Do the work only if the # of partitions is changing. Along with being @@ -1869,9 +1869,10 @@ int GPTData::SetGPTSize(uint32_t numEntries) { if (partitions != NULL) { // existing partitions; copy them over GetPartRange(&i, &high); if (numEntries < (high + 1)) { // Highest entry too high for new # - printf("The highest-numbered partition is %lu, which is greater than the requested\n" - "partition table size of %d; cannot resize. Perhaps sorting will help.\n", - (unsigned long) (high + 1), numEntries); + cout << "The highest-numbered partition is " << high + 1 + << ", which is greater than the requested\n" + << "partition table size of " << numEntries + << "; cannot resize. Perhaps sorting will help.\n"; allOK = 0; } else { // go ahead with copy if (numEntries < mainHeader.numParts) @@ -1896,7 +1897,7 @@ int GPTData::SetGPTSize(uint32_t numEntries) { if (diskSize > 0) CheckGPTSize(); } else { // Bad memory allocation - fprintf(stderr, "Error allocating memory for partition table!\n"); + cerr << "Error allocating memory for partition table!\n"; allOK = 0; } // if/else } // if/else @@ -1930,7 +1931,7 @@ int GPTData::DeletePartition(uint32_t partNum) { // Now delete the GPT partition partitions[partNum].BlankPartition(); } else { - fprintf(stderr, "Partition number %d out of range!\n", partNum + 1); + cerr << "Partition number " << partNum + 1 << " out of range!\n"; retval = 0; } // if/else return retval; @@ -2001,7 +2002,8 @@ int GPTData::ClearGPTData(void) { int goOn = 1, i; // Set up the partition table.... - free(partitions); + if (partitions != NULL) + free(partitions); partitions = NULL; SetGPTSize(NUM_GPT_ENTRIES); @@ -2051,11 +2053,12 @@ void GPTData::MoveSecondHeaderToEnd() { secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); } // GPTData::FixSecondHeaderLocation() -int GPTData::SetName(uint32_t partNum, char* theName) { +int GPTData::SetName(uint32_t partNum, string theName) { int retval = 1; - if (!IsFreePartNum(partNum)) - partitions[partNum].SetName((unsigned char*) theName); - else retval = 0; + + if (!IsFreePartNum(partNum)) { + partitions[partNum].SetName(theName); + } else retval = 0; return retval; } // GPTData::SetName @@ -2117,7 +2120,6 @@ int GPTData::Align(uint64_t* sector) { // Check to see that every sector between the earlier one and the // requested one is clear, and that it's not too early.... if (earlier >= mainHeader.firstUsableLBA) { -// printf("earlier is %llu, first usable is %llu\n", earlier, mainHeader.firstUsableLBA); sectorOK = 1; testSector = earlier; do { @@ -2125,7 +2127,6 @@ int GPTData::Align(uint64_t* sector) { } while ((sectorOK == 1) && (testSector < *sector)); if (sectorOK == 1) { *sector = earlier; -// printf("Moved sector earlier.\n"); } // if } // if firstUsableLBA check @@ -2138,22 +2139,21 @@ int GPTData::Align(uint64_t* sector) { } while ((sectorOK == 1) && (testSector > *sector)); if (sectorOK == 1) { *sector = later; -// printf("Moved sector later\n"); } // if } // if // If sector was changed successfully, inform the user of this fact. // Otherwise, notify the user that it couldn't be done.... if (sectorOK == 1) { - printf("Information: Moved requested sector from %llu to %llu for\n" - "alignment purposes.\n", - (unsigned long long) original, (unsigned long long) *sector); + cout << "Information: Moved requested sector from " << original << " to " + << *sector << " for\nalignment purposes.\n"; if (!beQuiet) - printf("Use 'l' on the experts' menu to adjust alignment\n"); + cout << "Use 'l' on the experts' menu to adjust alignment\n"; } else { - printf("Information: Sector not aligned on %d-sector boundary and could not be moved.\n" - "If you're using a Western Digital Advanced Format or similar disk with\n" - "underlying 4096-byte sectors, performance may suffer.\n", sectorAlignment); + cout << "Information: Sector not aligned on " << sectorAlignment + << "-sector boundary and could not be moved.\n" + << "If you're using a Western Digital Advanced Format or similar disk with\n" + << "underlying 4096-byte sectors, performance may suffer.\n"; retval = 0; } // if/else } // if @@ -2408,8 +2408,8 @@ void GPTData::ReversePartitionBytes() { // if the function is called out of order. Unfortunately, it'll also // mismatch if there's data corruption. if ((mainHeader.signature != GPT_SIGNATURE) && (IsLittleEndian() == 0)) { - printf("GPT signature mismatch in GPTData::ReversePartitionBytes(). This indicates\n" - "data corruption or a misplaced call to this function.\n"); + cerr << "GPT signature mismatch in GPTData::ReversePartitionBytes(). This indicates\n" + << "data corruption or a misplaced call to this function.\n"; } // if signature mismatch.... for (i = 0; i < mainHeader.numParts; i++) { partitions[i].ReversePartBytes(); @@ -2430,42 +2430,41 @@ int SizesOK(void) { int allOK = 1; if (sizeof(uint8_t) != 1) { - fprintf(stderr, "uint8_t is %lu bytes, should be 1 byte; aborting!\n", sizeof(uint8_t)); + cerr << "uint8_t is " << sizeof(uint8_t) << " bytes, should be 1 byte; aborting!\n"; allOK = 0; } // if if (sizeof(uint16_t) != 2) { - fprintf(stderr, "uint16_t is %lu bytes, should be 2 bytes; aborting!\n", sizeof(uint16_t)); + cerr << "uint16_t is " << sizeof(uint16_t) << " bytes, should be 2 bytes; aborting!\n"; allOK = 0; } // if if (sizeof(uint32_t) != 4) { - fprintf(stderr, "uint32_t is %lu bytes, should be 4 bytes; aborting!\n", sizeof(uint32_t)); + cerr << "uint32_t is " << sizeof(uint32_t) << " bytes, should be 4 bytes; aborting!\n"; allOK = 0; } // if if (sizeof(uint64_t) != 8) { - fprintf(stderr, "uint64_t is %lu bytes, should be 8 bytes; aborting!\n", sizeof(uint64_t)); + cerr << "uint64_t is " << sizeof(uint64_t) << " bytes, should be 8 bytes; aborting!\n"; allOK = 0; } // if if (sizeof(struct MBRRecord) != 16) { - fprintf(stderr, "MBRRecord is %lu bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord)); + cerr << "MBRRecord is " << sizeof(MBRRecord) << " bytes, should be 16 bytes; aborting!\n"; allOK = 0; } // if if (sizeof(struct TempMBR) != 512) { - fprintf(stderr, "TempMBR is %lu bytes, should be 512 bytes; aborting!\n", sizeof(TempMBR)); + cerr << "TempMBR is " << sizeof(TempMBR) << " bytes, should be 512 bytes; aborting!\n"; allOK = 0; } // if if (sizeof(struct GPTHeader) != 512) { - fprintf(stderr, "GPTHeader is %lu bytes, should be 512 bytes; aborting!\n", sizeof(GPTHeader)); + cerr << "GPTHeader is " << sizeof(GPTHeader) << " bytes, should be 512 bytes; aborting!\n"; allOK = 0; } // if if (sizeof(GPTPart) != 128) { - fprintf(stderr, "GPTPart is %lu bytes, should be 128 bytes; aborting!\n", sizeof(GPTPart)); + cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n"; allOK = 0; } // if -// Determine endianness; set allOK = 0 if running on big-endian hardware + // Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware if (IsLittleEndian() == 0) { - fprintf(stderr, "\aRunning on big-endian hardware. Big-endian support is new and poorly" - " tested!\nBeware!\n"); - // allOK = 0; + cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly" + " tested!\n"; } // if return (allOK); } // SizesOK() diff --git a/gpt.h b/gpt.h index 1d605b5..76f1678 100644 --- a/gpt.h +++ b/gpt.h @@ -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); diff --git a/gptpart.cc b/gptpart.cc index 076f115..c6504c1 100644 --- a/gptpart.cc +++ b/gptpart.cc @@ -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)); - - 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 << "Partition GUID code: " << GUIDToStr(partitionType); + cout << " (" << typeHelper.GUIDToName(partitionType) << ")\n"; + cout << "Partition unique GUID: " << GUIDToStr(uniqueGUID) << "\n"; + + 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 diff --git a/gptpart.h b/gptpart.h index 2ae27e3..dc499b9 100644 --- a/gptpart.h +++ b/gptpart.h @@ -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); diff --git a/mbr.cc b/mbr.cc index 029b576..411cae5 100644 --- a/mbr.cc +++ b/mbr.cc @@ -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; diff --git a/mbr.h b/mbr.h index c8711fc..9fc749b 100644 --- a/mbr.h +++ b/mbr.h @@ -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); diff --git a/parttypes.cc b/parttypes.cc index 20289c6..d4e4a92 100644 --- a/parttypes.cc +++ b/parttypes.cc @@ -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() diff --git a/parttypes.h b/parttypes.h index 5a34d30..7e6d892 100644 --- a/parttypes.h +++ b/parttypes.h @@ -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); }; diff --git a/sgdisk.cc b/sgdisk.cc index 5c346b7..14f95e5 100644 --- a/sgdisk.cc +++ b/sgdisk.cc @@ -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() diff --git a/support.cc b/support.cc index 388b71a..3e4ad6c 100644 --- a/support.cc +++ b/support.cc @@ -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; - - 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 + char theString[40]; + + 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. diff --git a/support.h b/support.h index 3a102ae..79e62a9 100644 --- a/support.h +++ b/support.h @@ -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 -- GitLab