Nearing 0.6.2 release; Windows version now works.

This commit is contained in:
srs5694
2010-01-28 21:10:52 -05:00
parent 91544e13fb
commit 0a6973119c
17 changed files with 295 additions and 285 deletions

View File

@@ -1,6 +1,10 @@
0.6.2 (?/??/2010):
------------------
- The change-type ('t' on main menu) option now changes the partition's
name *IF* the current name is the generic one for the partition type.
If the current name is not the generic name, it is NOT changed.
- 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.

View File

@@ -19,9 +19,6 @@ gdisk: $(LIB_OBJS) gdisk.o
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk
wipegpt: $(LIB_OBJS) wipegpt.o
$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
lint: #no pre-reqs
lint $(SRCS)

View File

@@ -1,7 +1,8 @@
CC=/usr/bin/i586-mingw32msvc-gcc
CXX=/usr/bin/i586-mingw32msvc-g++
STRIP=/usr/bin/i586-mingw32msvc-strip
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -DMINGW -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
CXXFLAGS=-O2 -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
LIB_NAMES=gptpart bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
@@ -17,16 +18,16 @@ gdisk: $(LIB_OBJS) gdisk.o
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk.exe
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk
wipegpt: $(LIB_OBJS) wipegpt.o
$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk.exe
lint: #no pre-reqs
lint $(SRCS)
clean: #no pre-reqs
rm -f core *.o *~ gdisk sgdisk
rm -f core *.o *~ gdisk.exe sgdisk.exe
strip: #no pre-reqs
$(STRIP) gdisk.exe
# what are the source dependencies
depend: $(SRCS)

6
bsd.cc
View File

@@ -43,12 +43,12 @@ 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. Returns 1 on success, 0 on failure.
int BSDData::ReadBSDData(string *device, uint64_t startSector, uint64_t endSector) {
int BSDData::ReadBSDData(const string & device, uint64_t startSector, uint64_t endSector) {
int allOK = 1;
DiskIO myDisk;
if (*device != "") {
if (myDisk.OpenForRead(*device)) {
if (device != "") {
if (myDisk.OpenForRead(device)) {
allOK = ReadBSDData(&myDisk, startSector, endSector);
} else {
allOK = 0;

2
bsd.h
View File

@@ -72,7 +72,7 @@ class BSDData {
public:
BSDData(void);
~BSDData(void);
int ReadBSDData(string *deviceFilename, uint64_t startSector, uint64_t endSector);
int ReadBSDData(const string & deviceFilename, uint64_t startSector, uint64_t endSector);
int ReadBSDData(DiskIO *myDisk, uint64_t startSector, uint64_t endSector);
void ReverseMetaBytes(void);
void DisplayBSDData(void);

View File

@@ -42,9 +42,9 @@ void DiskIO::MakeRealName(void) {
if ((colonPos != string::npos) && (colonPos <= 3)) {
realFilename = "\\\\.\\physicaldrive";
realFilename += userFilename.substr(0, colonPos);
} else {
realFilename = userFilename;
} // if/else
printf("Exiting DiskIO::MakeRealName(); translated '%s' ", userFilename.c_str());
printf("to '%s'\n", realFilename.c_str());
} // DiskIO::MakeRealName()
// Open the currently on-record file for reading
@@ -60,12 +60,11 @@ int DiskIO::OpenForRead(void) {
} // if
if (shouldOpen) {
printf("Opening '%s' for reading.\n", realFilename.c_str());
fd = CreateFile(realFilename.c_str(),GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_HANDLE_VALUE) {
CloseHandle(fd);
fprintf(stderr, "Problem opening %s for reading!\n", realFilename.c_str());
cerr << "Problem opening " << realFilename << " for reading!\n";
realFilename = "";
userFilename = "";
isOpen = 0;
@@ -94,11 +93,12 @@ int DiskIO::OpenForWrite(void) {
FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_HANDLE_VALUE) {
CloseHandle(fd);
isOpen = 1;
openForWrite = 1;
} else {
isOpen = 0;
openForWrite = 0;
errno = GetLastError();
} else {
isOpen = 1;
openForWrite = 1;
} // if/else
return isOpen;
} // DiskIO::OpenForWrite(void)
@@ -133,6 +133,7 @@ int DiskIO::GetBlockSize(void) {
__out LPDWORD lpTotalNumberOfClusters
); */
// err = GetDiskFreeSpace(realFilename.c_str(), &junk1, &blockSize, &junk2, &junk3);
// Above call is fubared -- returns weird values for blockSize....
err = 1;
blockSize = 512;
@@ -142,9 +143,9 @@ int DiskIO::GetBlockSize(void) {
// file, so don't display the warning message....
// 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",
GetLastError(), SECTOR_SIZE);
if (errno != 267) { // 267 is returned on ordinary files
cerr << "\aError " << GetLastError() << " when determining sector size! "
<< "Setting sector size to " << SECTOR_SIZE << "\n";
} // if
} // if (err == -1)
} // if (isOpen)
@@ -155,21 +156,26 @@ int DiskIO::GetBlockSize(void) {
// Resync disk caches so the OS uses the new partition table. This code varies
// a lot from one OS to another.
void DiskIO::DiskSync(void) {
int i;
DWORD i;
GET_LENGTH_INFORMATION buf;
// If disk isn't open, try to open it....
if (!isOpen) {
OpenForRead();
if (!openForWrite) {
OpenForWrite();
} // if
if (isOpen) {
#ifndef MINGW
sync();
#endif
#ifdef MINGW
printf("Warning: I don't know how to sync disks in Windows! The old partition table is\n"
"probably still in use!\n");
#endif
if (DeviceIoControl(fd, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, &buf, sizeof(buf), &i, NULL) == 0) {
cout << "Disk synchronization failed! The computer may use the old partition table\n"
<< "until you reboot or remove and re-insert the disk!\n";
} else {
cout << "Disk synchronization succeeded! The computer should now use the new\n"
<< "partition table.\n";
} // if/else
} else {
cout << "Unable to open the disk for synchronization operation! The computer will\n"
<< "continue to use the old partition table until you reboot or remove and\n"
<< "re-insert the disk!\n";
} // if (isOpen)
} // DiskIO::DiskSync()
@@ -186,22 +192,11 @@ int DiskIO::Seek(uint64_t sector) {
} // if
if (isOpen) {
bytePos = sector * (uint64_t) GetBlockSize();
lowBits = (uint32_t) (bytePos / UINT64_C(4294967296));
highBits = (uint32_t) (bytePos % UINT64_C(4294967296));
seekTo.LowPart = lowBits;
seekTo.HighPart = highBits;
// seekTo.QuadPart = (LONGLONG) (sector * (uint64_t) GetBlockSize());
/* printf("In DiskIO::Seek(), sector = %llu, ", sector);
printf("block size = %d, ", GetBlockSize());
printf("seekTo.QuadPart = %lld\n", seekTo.QuadPart);
printf(" seekTo.LowPart = %lu, ", seekTo.LowPart);
printf("seekTo.HighPart = %lu\n", seekTo.HighPart); */
seekTo.QuadPart = sector * (uint64_t) GetBlockSize();
retval = SetFilePointerEx(fd, seekTo, NULL, FILE_BEGIN);
if (retval == 0) {
errno = GetLastError();
fprintf(stderr, "Error when seeking to %lld! Error is %d\n",
seekTo.QuadPart, errno);
cerr << "Error when seeking to " << seekTo.QuadPart << "! Error is " << errno << "\n";
retval = 0;
} // if
} // if
@@ -235,9 +230,7 @@ int DiskIO::Read(void* buffer, int numBytes) {
} // if/else
// Read the data into temporary space, then copy it to buffer
// retval = read(fd, tempSpace, numBlocks * blockSize);
ReadFile(fd, tempSpace, numBlocks * blockSize, &retval, NULL);
printf("In DiskIO::Read(), have read %d bytes.\n", (int) retval);
for (i = 0; i < numBytes; i++) {
((char*) buffer)[i] = tempSpace[i];
} // for
@@ -284,7 +277,6 @@ int DiskIO::Write(void* buffer, int numBytes) {
for (i = numBytes; i < numBlocks * blockSize; i++) {
tempSpace[i] = 0;
} // for
// retval = write(fd, tempSpace, numBlocks * blockSize);
WriteFile(fd, tempSpace, numBlocks * blockSize, &numWritten, NULL);
retval = (int) numWritten;
@@ -300,8 +292,7 @@ int DiskIO::Write(void* buffer, int numBytes) {
// Returns the size of the disk in blocks.
uint64_t DiskIO::DiskSize(int *err) {
uint64_t sectors = 0; // size in sectors
off_t bytes = 0; // size in bytes
struct stat64 st;
DWORD bytes, moreBytes; // low- and high-order bytes of file size
GET_LENGTH_INFORMATION buf;
DWORD i;
@@ -316,30 +307,18 @@ uint64_t DiskIO::DiskSize(int *err) {
// on Linux, but I had some problems. IIRC, it ran OK on 32-bit
// systems but not on 64-bit. Keep this in mind in case of
// 32/64-bit issues on MacOS....
/* HANDLE fin;
fin = CreateFile(realFilename.c_str(), GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); */
if (DeviceIoControl(fd, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, sizeof(buf), &i, NULL)) {
sectors = (uint64_t) buf.Length.QuadPart / GetBlockSize();
// printf("disk_get_size_win32 IOCTL_DISK_GET_LENGTH_INFO = %llu\n",
// (long long unsigned) sectors);
} else {
fprintf(stderr, "Couldn't determine disk size!\n");
}
*err = 0;
} else { // doesn't seem to be a disk device; assume it's an image file....
bytes = GetFileSize(fd, &moreBytes);
sectors = ((uint64_t) bytes + ((uint64_t) moreBytes) * UINT32_MAX) / GetBlockSize();
*err = 0;
} // if
} else {
*err = -1;
sectors = 0;
} // if/else (isOpen)
/* // 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
// fstat() gives us....
if ((sectors == 0) || (*err == -1)) {
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");
sectors = bytes / UINT64_C(512);
} // if
} // if */
} // if (isOpen)
return sectors;
} // DiskIO::DiskSize()

View File

@@ -15,7 +15,7 @@
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
#ifdef MINGW
#ifdef _WIN32
#include <windows.h>
#include <winioctl.h>
#define fstat64 fstat
@@ -52,7 +52,7 @@ DiskIO::~DiskIO(void) {
} // destructor
// Open a disk device for reading. Returns 1 on success, 0 on failure.
int DiskIO::OpenForRead(string filename) {
int DiskIO::OpenForRead(const string & filename) {
int shouldOpen = 1;
if (isOpen) { // file is already open
@@ -74,7 +74,7 @@ int DiskIO::OpenForRead(string filename) {
// Open a disk for reading and writing by filename.
// Returns 1 on success, 0 on failure.
int DiskIO::OpenForWrite(string filename) {
int DiskIO::OpenForWrite(const string & filename) {
int retval = 0;
if ((isOpen) && (openForWrite) && ((filename == realFilename) || (filename == userFilename))) {
@@ -151,7 +151,7 @@ int DiskIO::FindAlignment(void) {
} // DiskIO::FindAlignment(int) */
// The same as FindAlignment(int), but opens and closes a device by filename
int DiskIO::FindAlignment(string filename) {
int DiskIO::FindAlignment(const string & filename) {
int fd;
int retval = 1;

View File

@@ -18,7 +18,7 @@
#include <string>
#include <stdint.h>
#include <sys/types.h>
#ifdef MINGW
#ifdef _WIN32
#include <windows.h>
#include <winioctl.h>
#else
@@ -52,7 +52,7 @@ class DiskIO {
int isOpen;
int openForWrite;
uint8_t *sectorData;
#ifdef MINGW
#ifdef _WIN32
HANDLE fd;
#else
int fd;
@@ -62,9 +62,9 @@ class DiskIO {
~DiskIO(void);
void MakeRealName(void);
int OpenForRead(string filename);
int OpenForRead(const string & filename);
int OpenForRead(void);
int OpenForWrite(string filename);
int OpenForWrite(const string & filename);
int OpenForWrite(void);
void Close();
int Seek(uint64_t sector);
@@ -73,7 +73,7 @@ class DiskIO {
void DiskSync(void); // resync disk caches to use new partitions
int GetBlockSize(void);
int FindAlignment(void);
int FindAlignment(string filename);
int FindAlignment(const string & filename);
int IsOpen(void) {return isOpen;}
int IsOpenForWrite(void) {return openForWrite;}

View File

@@ -2,7 +2,7 @@
.\" May be distributed under the GNU General Public License
.TH "GDISK" "8" "0.5.3" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator for Linux and Unix
gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS"
.BI "gdisk "
[ \-l ]
@@ -453,10 +453,8 @@ mid-physical-sector, though, performance can suffer on such drives, since
important filesystem data structures can span physical sectors on the disk.
To minimize such problems, GPT fdisk aligns the start of partitions on the
boundary of presumed physical sectors. You can set the number of logical
sectors per physical sector with this option. The default is 8, except on
Linux 2.6.32 and later, in which case it's read from the disk. A value of 8
will result in a tiny amount of wasted disk space on older disks with true
512-byte sectors but will otherwise be harmless.
sectors per physical sector with this option. The default is 1 on disks
smaller than 800GB and 8 on larger disks.
.TP
.B m

View File

@@ -34,6 +34,17 @@ int main(int argc, char* argv[]) {
if (argc == 2) { // basic usage
if (SizesOK()) {
#ifdef _WIN32
cout << "\a************************************************************************\n"
<< "Most versions of Windows cannot boot from a GPT disk, and most varieties\n"
<< "prior to Vista cannot read GPT disks. Therefore, you should exit now\n"
<< "unless you understand the implications of converting MBR to GPT, editing\n"
<< "an existing GPT disk, or creating a new GPT disk layout!\n"
<< "************************************************************************\n\n";
cout << "Are you SURE you want to continue? ";
if (GetYN() != 'Y')
exit(0);
#endif
doMore = theGPT.LoadPartitions(argv[1]);
if (doMore) {
MainMenu(argv[1], &theGPT);

32
gpt.cc
View File

@@ -239,7 +239,7 @@ int GPTData::Verify(void) {
<< largestSegment << " (" << BytesToSI(largestSegment * (uint64_t) blockSize)
<< ") in size\n";
} else {
cout << "\nIdentified %d problems!\n", problems;
cout << "\nIdentified " << problems << " problems!\n";
} // if/else
return (problems);
@@ -497,7 +497,7 @@ int GPTData::FindOverlaps(void) {
for (i = 1; i < mainHeader.numParts; i++) {
for (j = 0; j < i; j++) {
if (partitions[i].DoTheyOverlap(&partitions[j])) {
if (partitions[i].DoTheyOverlap(partitions[j])) {
problems++;
cout << "\nProblem: partitions " << i + 1 << " and " << j + 1 << " overlap:\n";
cout << " Partition " << i + 1 << ": " << partitions[i].GetFirstLBA()
@@ -550,7 +550,7 @@ void GPTData::PartitionScan(void) {
} // GPTData::PartitionScan()
// Read GPT data from a disk.
int GPTData::LoadPartitions(string deviceFilename) {
int GPTData::LoadPartitions(const string & deviceFilename) {
int err;
int allOK = 1, i;
uint64_t firstBlock, lastBlock;
@@ -636,7 +636,7 @@ int GPTData::LoadPartitions(string deviceFilename) {
// succeeded, 0 if there are obvious problems....
int GPTData::ForceLoadGPTData(void) {
int allOK = 1, validHeaders;
off_t seekTo;
uint64_t seekTo;
uint8_t* storage;
uint32_t newCRC, sizeOfParts;
@@ -839,7 +839,7 @@ int GPTData::SaveGPTData(int quiet) {
char answer, line[256];
uint64_t secondTable;
uint32_t numParts;
off_t offset;
uint64_t offset;
if (device == "") {
cerr << "Device not defined.\n";
@@ -936,7 +936,7 @@ int GPTData::SaveGPTData(int quiet) {
// Now seek to near the end to write the secondary GPT....
if (allOK) {
offset = (off_t) secondTable;
offset = (uint64_t) secondTable;
if (myDisk.Seek(offset) != 1) {
allOK = 0;
cerr << "Unable to seek to end of disk! Perhaps the 'e' option on the experts' menu\n"
@@ -998,12 +998,11 @@ 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(string filename) {
int fd, allOK = 1;
int GPTData::SaveGPTBackup(const string & filename) {
int allOK = 1;
uint32_t numParts;
DiskIO backupFile;
// if ((fd = open(filename, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) {
if (backupFile.OpenForWrite(filename)) {
// Reverse the byte order, if necessary....
numParts = mainHeader.numParts;
@@ -1066,13 +1065,12 @@ int GPTData::SaveGPTBackup(string 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(string filename) {
int fd, allOK = 1, val;
int GPTData::LoadGPTBackup(const string & filename) {
int allOK = 1, val;
uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC;
int littleEndian = 1;
DiskIO backupFile;
// if ((fd = open(filename, O_RDONLY)) != -1) {
if (backupFile.OpenForRead(filename)) {
if (IsLittleEndian() == 0)
littleEndian = 0;
@@ -1473,7 +1471,7 @@ WhichToUse GPTData::UseWhichPartitions(void) {
cout << "\n**********************************************************************\n"
<< "Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n"
<< "to GPT format.";
if (!justLooking) {
if ((!justLooking) && (!beQuiet)) {
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!";
@@ -1493,10 +1491,9 @@ WhichToUse GPTData::UseWhichPartitions(void) {
cout << "Found valid GPT with hybrid MBR; using GPT.\n";
} // if
if ((state == gpt_valid) && (mbrState == invalid)) {
cout << "\aFound valid GPT with corrupt MBR; using GPT and will create new\n"
cout << "\aFound valid GPT with corrupt MBR; using GPT and will write new\n"
<< "protective MBR on save.\n";
which = use_gpt;
protectiveMBR.MakeProtectiveMBR();
} // if
if ((state == gpt_valid) && (mbrState == mbr)) {
if (!beQuiet) {
@@ -1506,7 +1503,6 @@ WhichToUse GPTData::UseWhichPartitions(void) {
which = use_mbr;
} else if (answer == 2) {
which = use_gpt;
protectiveMBR.MakeProtectiveMBR();
cout << "Using GPT and creating fresh protective MBR.\n";
} else which = use_new;
} else which = use_abort;
@@ -1612,7 +1608,7 @@ int GPTData::XFormDisklabel(int i) {
// If all is OK, read the disklabel and convert it.
if (goOn) {
goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(),
goOn = disklabel.ReadBSDData(device, partitions[partNum].GetFirstLBA(),
partitions[partNum].GetLastLBA());
if ((goOn) && (disklabel.IsDisklabel())) {
numDone = XFormDisklabel(&disklabel, startPart);
@@ -2053,7 +2049,7 @@ void GPTData::MoveSecondHeaderToEnd() {
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
} // GPTData::FixSecondHeaderLocation()
int GPTData::SetName(uint32_t partNum, string theName) {
int GPTData::SetName(uint32_t partNum, const string & theName) {
int retval = 1;
if (!IsFreePartNum(partNum)) {

12
gpt.h
View File

@@ -93,15 +93,15 @@ public:
int FindOverlaps(void);
// Load or save data from/to disk
int LoadMBR(string f) {return protectiveMBR.ReadMBRData(f);}
int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);}
void PartitionScan(void);
int LoadPartitions(string deviceFilename);
int LoadPartitions(const string & deviceFilename);
int ForceLoadGPTData(void);
int LoadMainTable(void);
int LoadSecondTableAsMain(void);
int SaveGPTData(int quiet = 0);
int SaveGPTBackup(string filename);
int LoadGPTBackup(string filename);
int SaveGPTBackup(const string & filename);
int LoadGPTBackup(const 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, string theName = "");
int SetName(uint32_t partNum, const string & theName = "");
void SetDiskGUID(GUIDData newGUID);
int SetPartitionGUID(uint32_t pn, GUIDData theGUID);
int ChangePartType(uint32_t pn, uint16_t hexCode);
@@ -170,7 +170,7 @@ public:
WhichToUse WhichWasUsed(void) {return whichWasUsed;}
// Endianness functions
void ReverseHeaderBytes(struct GPTHeader* header); // for endianness
void ReverseHeaderBytes(struct GPTHeader* header);
void ReversePartitionBytes(); // for endianness
}; // class GPTData

View File

@@ -35,17 +35,6 @@ GPTPart::GPTPart(void) {
GPTPart::~GPTPart(void) {
} // destructor
// Return partition's name field, converted to a C++ ASCII string
string GPTPart::GetName(void) {
string theName;
int i;
for (i = 0; i < NAME_SIZE; i += 2) {
theName += name[i];
} // for
return theName;
} // GPTPart::GetName()
// Return the gdisk-specific two-byte hex code for the partition
uint16_t GPTPart::GetHexType(void) {
return typeHelper.GUIDToID(partitionType);
@@ -66,18 +55,30 @@ uint64_t GPTPart::GetLengthLBA(void) {
return length;
} // GPTPart::GetLengthLBA()
GPTPart & GPTPart::operator=(const GPTPart & orig) {
// Return partition's name field, converted to a C++ ASCII string
string GPTPart::GetName(void) {
string theName;
int i;
partitionType = orig.partitionType;
uniqueGUID = orig.uniqueGUID;
firstLBA = orig.firstLBA;
lastLBA = orig.lastLBA;
attributes = orig.attributes;
for (i = 0; i < NAME_SIZE; i++)
name[i] = orig.name[i];
return *this;
} // assignment operator
theName = "";
for (i = 0; i < NAME_SIZE; i += 2) {
if (name[i] != '\0')
theName += name[i];
} // for
return theName;
} // GPTPart::GetName()
// Set the type code to the specified one. Also changes the partition
// name *IF* the current name is the generic one for the current partition
// type.
void GPTPart::SetType(struct GUIDData t) {
int nameSame = 1, currentLength, i;
if (GetName() == typeHelper.GUIDToName(partitionType)) {
SetName(typeHelper.GUIDToName(t));
} // if
partitionType = t;
} // GPTPart::SetType()
// Sets the unique GUID to a value of 0 or a random value,
// depending on the parameter: 0 = 0, anything else = random
@@ -93,138 +94,11 @@ void GPTPart::SetUniqueGUID(int zeroOrRandom) {
}
} // GPTPart::SetUniqueGUID()
// Blank (delete) a single partition
void GPTPart::BlankPartition(void) {
int j;
GUIDData zeroGUID;
zeroGUID.data1 = 0;
zeroGUID.data2 = 0;
uniqueGUID = zeroGUID;
partitionType = zeroGUID;
firstLBA = 0;
lastLBA = 0;
attributes = 0;
for (j = 0; j < NAME_SIZE; j++)
name[j] = '\0';
} // GPTPart::BlankPartition
// Returns 1 if the two partitions overlap, 0 if they don't
int GPTPart::DoTheyOverlap(GPTPart* other) {
int theyDo = 0;
// Don't bother checking unless these are defined (both start and end points
// are 0 for undefined partitions, so just check the start points)
if ((firstLBA != 0) && (other->firstLBA != 0)) {
if ((firstLBA < other->lastLBA) && (lastLBA >= other->firstLBA))
theyDo = 1;
if ((other->firstLBA < lastLBA) && (other->lastLBA >= firstLBA))
theyDo = 1;
} // if
return (theyDo);
} // GPTPart::DoTheyOverlap()
// Reverse the bytes of integral data types; used on big-endian systems.
void GPTPart::ReversePartBytes(void) {
ReverseBytes(&partitionType.data1, 8);
ReverseBytes(&partitionType.data2, 8);
ReverseBytes(&uniqueGUID.data1, 8);
ReverseBytes(&uniqueGUID.data2, 8);
ReverseBytes(&firstLBA, 8);
ReverseBytes(&lastLBA, 8);
ReverseBytes(&attributes, 8);
} // GPTPart::ReverseBytes()
// Display summary information; does nothing if the partition is empty.
void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
string sizeInSI;
int i;
if (firstLBA != 0) {
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) {
uint64_t size;
if (firstLBA != 0) {
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);
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()
/****************************************
* Functions requiring user interaction *
****************************************/
// Change the type code on the partition.
void GPTPart::ChangeType(void) {
char line[255];
char* junk;
int typeNum = 0xFFFF;
GUIDData newType;
cout << "Current type is '" << GetNameType() << "'\n";
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
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'))
typeHelper.ShowTypes();
if (line[0] == '\n') {
typeNum = 0x0700;
} // if
} // while
if (typeNum != 0) // user entered a code, so convert it
newType = typeHelper.IDToGUID((uint16_t) typeNum);
else // user wants to enter the GUID directly, so do that
newType = GetGUID();
partitionType = newType;
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 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(string theName) {
void GPTPart::SetName(const string & theName) {
char newName[NAME_SIZE]; // New name
char *junk;
int i;
@@ -256,6 +130,145 @@ void GPTPart::SetName(string theName) {
} // for
} // GPTPart::SetName()
GPTPart & GPTPart::operator=(const GPTPart & orig) {
int i;
partitionType = orig.partitionType;
uniqueGUID = orig.uniqueGUID;
firstLBA = orig.firstLBA;
lastLBA = orig.lastLBA;
attributes = orig.attributes;
for (i = 0; i < NAME_SIZE; i++)
name[i] = orig.name[i];
return *this;
} // assignment operator
// Display summary information; does nothing if the partition is empty.
void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
string sizeInSI;
int i;
if (firstLBA != 0) {
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) {
uint64_t size;
if (firstLBA != 0) {
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);
cout << "Partition size: " << size << " sectors ("
<< BytesToSI(size * ((uint64_t) blockSize)) << ")\n";
cout << "Attribute flags: ";
cout.fill('0');
cout.width(16);
cout << hex;
cout << attributes << "\n";
cout << dec;
cout << "Partition name: " << GetName() << "\n";
cout.fill(' ');
} // if
} // GPTPart::ShowDetails()
// Blank (delete) a single partition
void GPTPart::BlankPartition(void) {
int j;
GUIDData zeroGUID;
zeroGUID.data1 = 0;
zeroGUID.data2 = 0;
uniqueGUID = zeroGUID;
partitionType = zeroGUID;
firstLBA = 0;
lastLBA = 0;
attributes = 0;
for (j = 0; j < NAME_SIZE; j++)
name[j] = '\0';
} // GPTPart::BlankPartition
// Returns 1 if the two partitions overlap, 0 if they don't
int GPTPart::DoTheyOverlap(const GPTPart & other) {
int theyDo = 0;
// Don't bother checking unless these are defined (both start and end points
// are 0 for undefined partitions, so just check the start points)
if ((firstLBA != 0) && (other.firstLBA != 0)) {
if ((firstLBA < other.lastLBA) && (lastLBA >= other.firstLBA))
theyDo = 1;
if ((other.firstLBA < lastLBA) && (other.lastLBA >= firstLBA))
theyDo = 1;
} // if
return (theyDo);
} // GPTPart::DoTheyOverlap()
// Reverse the bytes of integral data types; used on big-endian systems.
void GPTPart::ReversePartBytes(void) {
ReverseBytes(&partitionType.data1, 8);
ReverseBytes(&partitionType.data2, 8);
ReverseBytes(&uniqueGUID.data1, 8);
ReverseBytes(&uniqueGUID.data2, 8);
ReverseBytes(&firstLBA, 8);
ReverseBytes(&lastLBA, 8);
ReverseBytes(&attributes, 8);
} // GPTPart::ReverseBytes()
/****************************************
* Functions requiring user interaction *
****************************************/
// Change the type code on the partition.
void GPTPart::ChangeType(void) {
char line[255];
char* junk;
int typeNum = 0xFFFF;
GUIDData newType;
cout << "Current type is '" << GetNameType() << "'\n";
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
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'))
typeHelper.ShowTypes();
if (line[0] == '\n') {
typeNum = 0x0700;
} // if
} // while
if (typeNum != 0) // user entered a code, so convert it
newType = typeHelper.IDToGUID((uint16_t) typeNum);
else // user wants to enter the GUID directly, so do that
newType = GetGUID();
SetType(newType);
cout << "Changed type of partition to '" << typeHelper.GUIDToName(partitionType) << "'\n";
} // GPTPart::ChangeType()
/***********************************
* Non-class but related functions *
***********************************/

View File

@@ -62,21 +62,21 @@ class GPTPart {
string GetName(void);
// Simple data assignment:
void SetType(struct GUIDData t) {partitionType = t;}
void SetType(uint16_t hex) {partitionType = typeHelper.IDToGUID(hex);}
void SetType(struct GUIDData t);
void SetType(uint16_t hex) {SetType(typeHelper.IDToGUID(hex));}
void SetUniqueGUID(struct GUIDData u) {uniqueGUID = u;}
void SetUniqueGUID(int zeroOrRandom);
void SetFirstLBA(uint64_t f) {firstLBA = f;}
void SetLastLBA(uint64_t l) {lastLBA = l;}
void SetAttributes(uint64_t a) {attributes = a;}
void SetName(string n);
void SetName(const string & n);
// Additional functions
GPTPart & operator=(const GPTPart & orig);
void ShowSummary(int partNum, uint32_t blockSize); // display summary information (1-line)
void ShowDetails(uint32_t blockSize); // display detailed information (multi-line)
void BlankPartition(void); // empty partition of data
int DoTheyOverlap(GPTPart* other); // returns 1 if there's overlap
int DoTheyOverlap(const GPTPart & other); // returns 1 if there's overlap
void ReversePartBytes(void); // reverse byte order of all integer fields
// Functions requiring user interaction

40
mbr.cc
View File

@@ -38,6 +38,7 @@ MBRData::MBRData(void) {
srand((unsigned int) time(NULL));
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL;
EmptyMBR();
} // MBRData default constructor
@@ -48,6 +49,7 @@ MBRData::MBRData(string filename) {
state = invalid;
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL;
srand((unsigned int) time(NULL));
// Try to read the specified partition table, but if it fails....
@@ -55,9 +57,10 @@ MBRData::MBRData(string filename) {
EmptyMBR();
device = "";
} // if
} // MBRData(char *filename) constructor
} // MBRData(string filename) constructor
MBRData::~MBRData(void) {
// delete myDisk;
} // MBRData destructor
/**********************
@@ -68,9 +71,11 @@ 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(string deviceFilename) {
int MBRData::ReadMBRData(const string & deviceFilename) {
int fd, allOK = 1;
if (myDisk == NULL)
myDisk = new DiskIO;
if (myDisk->OpenForRead(deviceFilename)) {
ReadMBRData(myDisk);
} else {
@@ -81,7 +86,7 @@ int MBRData::ReadMBRData(string deviceFilename) {
device = deviceFilename;
return allOK;
} // MBRData::ReadMBRData(char* deviceFilename)
} // MBRData::ReadMBRData(const string & deviceFilename)
// Read data from MBR. If checkBlockSize == 1 (the default), the block
// size is checked; otherwise it's set to the default (512 bytes).
@@ -93,6 +98,9 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
int err = 1;
TempMBR tempMBR;
if (myDisk != NULL)
delete myDisk;
myDisk = theDisk;
// Empty existing MBR data, including the logical partitions...
@@ -102,7 +110,7 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
if (myDisk->Read(&tempMBR, 512))
err = 0;
if (err) {
cerr << "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];
@@ -183,7 +191,7 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
} // for
} // if (hybrid detection code)
} // no initial error
} // MBRData::ReadMBRData(int fd)
} // MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize)
// This is a recursive function to read all the logical partitions, following the
// logical partition linked list from the disk and storing the basic data in the
@@ -252,14 +260,16 @@ int MBRData::ReadLogicalPart(uint32_t extendedStart,
// Write the MBR data to the default defined device. Note that this writes
// ONLY the MBR itself, not the logical partition data.
int MBRData::WriteMBRData(void) {
int allOK = 1, fd;
int allOK = 1;
if (myDisk->OpenForWrite(device) != 0) {
allOK = WriteMBRData(myDisk);
} else {
allOK = 0;
} // if/else
myDisk->Close();
if (myDisk != NULL) {
if (myDisk->OpenForWrite(device) != 0) {
allOK = WriteMBRData(myDisk);
} else {
allOK = 0;
} // if/else
myDisk->Close();
} else allOK = 0;
return allOK;
} // MBRData::WriteMBRData(void)
@@ -322,12 +332,12 @@ int MBRData::WriteMBRData(DiskIO *theDisk) {
} // for
}// if
return allOK;
} // MBRData::WriteMBRData(DiskIO theDisk)
} // MBRData::WriteMBRData(DiskIO *theDisk)
int MBRData::WriteMBRData(string deviceFilename) {
int MBRData::WriteMBRData(const string & deviceFilename) {
device = deviceFilename;
return WriteMBRData();
} // MBRData::WriteMBRData(char* deviceFilename)
} // MBRData::WriteMBRData(const string & deviceFilename)
/********************************************
* *

4
mbr.h
View File

@@ -80,7 +80,7 @@ public:
~MBRData(void);
// File I/O functions...
int ReadMBRData(string deviceFilename);
int ReadMBRData(const 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(string deviceFilename);
int WriteMBRData(const string & deviceFilename);
// Display data for user...
void DisplayMBRData(void);

View File

@@ -236,6 +236,7 @@ int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
// in an ugly way.
void PartTypes::ShowTypes(void) {
int colCount = 1; // column count
int i;
AType* thisType = allTypes;
cout.unsetf(ios::uppercase);
@@ -244,17 +245,16 @@ void PartTypes::ShowTypes(void) {
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) << " ";
for (i = 0; i < (19 - ((string) thisType->name).substr(0, 19).length()); i ++) cout << " ";
if ((colCount % 3) == 0)
cout << "\n";
colCount++;
} // if
thisType = thisType->next;
} // while
cout << "\n";
cout.fill(' ');
cout << "\n" << dec;
} // PartTypes::ShowTypes()
// Returns 1 if code is a valid extended MBR code, 0 if it's not
@@ -323,6 +323,7 @@ struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
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;
cout.fill(' ');
} // if (!found)
return theGUID;
} // PartTypes::IDToGUID()