Version 0.6.3 release. Big-endian bug fix, new GUID generation method,

architectural changes.
This commit is contained in:
srs5694
2010-02-04 00:55:30 -05:00
parent 20e2a97ae6
commit 6699b01eda
21 changed files with 469 additions and 523 deletions

View File

@@ -1,3 +1,30 @@
0.6.3 (2/3/2010):
------------------
- Fixed serious data corruption bug on big-endian (PowerPC and similar)
systems.
- Changed several GPT fdisk Solaris type codes to correct a duplicate
- Corrected error in GPT fdisk type codes for NetBSD LFS and NetBSD RAID;
they were identical, but I've now changed NetBSD RAID to A906, which
is unique.
- Added GUID for IBM General Parallel File System (GPFS) partition type
code. Somewhat arbitrarily set it to use the 7501 number (MBR code 0x75
is used by IBM PC/IX, so it's at least the right company, by my loose
numbering rules....).
- Improved GUID generation. Prior versions generated completely random
numbers for GUIDs. This works, but is technically a violation of the
spec. Unix versions now employ libuuid to generate GUIDs in a more
correct way. The Windows version still generates random numbers, though.
- Turned PartTypes class into a derived class of GUIDData, and renamed
it to PartType.
- Created new GUIDData class, to replace the original GUIDData struct.
0.6.2 (1/29/2010):
------------------

View File

@@ -2,7 +2,7 @@ CC=gcc
CXX=g++
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
LIB_NAMES=crc32 support gptpart mbr gpt bsd parttypes attributes diskio diskio-unix
LIB_NAMES=crc32 support guid gptpart mbr gpt bsd parttypes attributes diskio diskio-unix
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
@@ -11,10 +11,13 @@ DEPEND= makedepend $(CFLAGS)
all: gdisk sgdisk
gdisk: $(LIB_OBJS) gdisk.o
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk
$(CXX) $(LIB_OBJS) gdisk.o -L/opt/local/lib -L/usr/local/lib -luuid -o gdisk
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -luuid -lpopt -o sgdisk
testguid: $(LIB_OBJS) testguid.o
$(CXX) $(LIB_OBJS) testguid.o -o testguid
lint: #no pre-reqs
lint $(SRCS)

View File

@@ -2,8 +2,9 @@ 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 -Wall -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
CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -g
#CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
LIB_NAMES=guid gptpart bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
@@ -12,10 +13,10 @@ DEPEND= makedepend $(CFLAGS)
all: gdisk
gdisk: $(LIB_OBJS) gdisk.o
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk.exe
$(CXX) $(LIB_OBJS) gdisk.o -luuid -o gdisk.exe
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk.exe
$(CXX) $(LIB_OBJS) sgdisk.o -lpopt -o sgdisk.exe
lint: #no pre-reqs
lint $(SRCS)

35
README
View File

@@ -50,22 +50,31 @@ Installing
To compile GPT fdisk, you must have appropriate development tools
installed, most notably the GNU Compiler Collection (GCC) and its g++
compiler for C++. The sgdisk program also requires the popt library and its
development files (headers). Most Linux distributions install popt by
default, but you may need to install a package called popt-dev, popt-devel,
or something similar to obtain the header files. Mac OS users can find a
version of popt for Mac OS from http://popt.darwinports.com; however,
you'll first need to install DarwinPorts (instructions exist on the
preceding page). Alternatively, you can compile gdisk alone, without
sgdisk; gdisk doesn't require popt.
compiler for C++. In addition, note these requirements:
* On Linux, FreeBSD, and OS X, libuuid must be installed. This is the
standard for Linux and OS X, although you may need to install a package
called uuid-dev or something similar to get the headers. On FreeBSD, the
e2fsprogs-libuuid port must be installed.
* The sgdisk program also requires the popt library and its development
files (headers). Most Linux distributions install popt by default, but
you may need to install a package called popt-dev, popt-devel, or
something similar to obtain the header files. Mac OS users can find a
version of popt for Mac OS from http://popt.darwinports.com; however,
you'll first need to install DarwinPorts (instructions exist on the
preceding page). Alternatively, you can compile gdisk alone, without
sgdisk; gdisk doesn't require popt.
When all the necessary development tools and libraries are installed, you
can uncompress the package and type "make" at the command prompt in the
resulting directory. The result should be program files called gdisk and
sgdisk. Typing "make gdisk" or "make sgdisk" will compile only the requested
programs. You can use these programs in place or copy the files to a
suitable directory, such as /usr/local/sbin. You can copy the man pages
(gdisk.8 and sgdisk.8) to /usr/local/man/man8 to make them available.
resulting directory. (You may need to type "make -f Makefile.mac" on Mac OS
X or "make -f Makefile.mingw" to compile using MinGW for Windows.) The
result should be program files called gdisk and sgdisk. Typing "make gdisk"
or "make sgdisk" will compile only the requested programs. You can use
these programs in place or copy the files to a suitable directory, such as
/usr/local/sbin. You can copy the man pages (gdisk.8 and sgdisk.8) to
/usr/local/man/man8 to make them available.
Caveats
-------

View File

@@ -70,6 +70,15 @@ support of GPT, see Microsoft's Web page on the topic:
http://www.microsoft.com/whdc/device/storage/GPT_FAQ.mspx
The GUIDs generated by the program to uniquely identify disks and
partitions aren't "proper" GUIDs; they're purely random numbers. In
practice, this has caused me no problems; however, it's conceivable that
some disk utility will complain. The Unix versions of GPT fdisk generate
proper GUIDs, as of version 0.6.3. Note that this limitation applies ONLY
to the unique GUIDs for disks and partitions, not to the GUIDs used to
identify partition type codes; those are standardized and are handled
correctly by all versions of GPT fdisk.
Source Code and Compilation Issues
----------------------------------

View File

@@ -30,7 +30,7 @@ Attributes::Attributes(void) {
} // for
// Now reset those names that are defined....
atNames[0] = "system partition";
atNames[0] = "system partition"; // required for computer to operate
atNames[60] = "read-only";
atNames[62] = "hidden";
atNames[63] = "do not automount";

4
bsd.cc
View File

@@ -291,7 +291,7 @@ GPTPart BSDData::AsGPT(int i) {
guid.SetFirstLBA(sectorOne);
guid.SetLastLBA(sectorEnd);
// Now set a random unique GUID for the partition....
guid.SetUniqueGUID(1);
guid.RandomizeUniqueGUID();
// ... zero out the attributes and name fields....
guid.SetAttributes(UINT64_C(0));
// Most BSD disklabel type codes seem to be archaic or rare.
@@ -321,7 +321,7 @@ GPTPart BSDData::AsGPT(int i) {
guid.SetType(0x0700); break;
} // switch
// Set the partition name to the name of the type code....
guid.SetName(guid.GetNameType());
guid.SetName(guid.GetTypeName());
} // if
return guid;
} // BSDData::AsGPT()

View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH "GDISK" "8" "0.5.3" "Roderick W. Smith" "GPT fdisk Manual"
.TH "GDISK" "8" "0.6.3" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS"

View File

@@ -29,6 +29,7 @@ int main(int argc, char* argv[]) {
GPTData theGPT;
int doMore = 1;
char* device = NULL;
PartType typeHelper; // unused, but necessary to initialize partition type linked list
cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n";
@@ -76,7 +77,7 @@ void MainMenu(string filename, struct GPTData* theGPT) {
char command, line[255], buFile[255];
char* junk;
int goOn = 1;
PartTypes typeHelper;
PartType typeHelper;
uint32_t temp1, temp2;
do {
@@ -105,7 +106,7 @@ void MainMenu(string filename, struct GPTData* theGPT) {
theGPT->ShowDetails();
break;
case 'l': case 'L':
typeHelper.ShowTypes();
typeHelper.ShowAllTypes();
break;
case 'n': case 'N':
theGPT->CreatePartition();
@@ -177,7 +178,6 @@ void ShowCommands(void) {
void RecoveryMenu(string filename, struct GPTData* theGPT) {
char command, line[255], buFile[255];
char* junk;
PartTypes typeHelper;
uint32_t temp1;
int goOn = 1;
@@ -303,10 +303,10 @@ void ShowRecoveryCommands(void) {
void ExpertsMenu(string filename, struct GPTData* theGPT) {
char command, line[255];
char* junk;
PartTypes typeHelper;
uint32_t pn;
uint32_t temp1, temp2;
int goOn = 1;
GUIDData aGUID;
do {
cout << "\nExpert command (? for help): ";
@@ -325,7 +325,7 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
pn = theGPT->GetPartNum();
cout << "Enter the partition's new unique GUID:\n";
theGPT->SetPartitionGUID(pn, GetGUID());
theGPT->SetPartitionGUID(pn, aGUID.GetGUIDFromUser());
} else cout << "No partitions\n";
break;
case 'd': case 'D':
@@ -338,7 +338,7 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
break;
case 'g': case 'G':
cout << "Enter the disk's unique GUID:\n";
theGPT->SetDiskGUID(GetGUID());
theGPT->SetDiskGUID(aGUID.GetGUIDFromUser());
break;
case 'i': case 'I':
theGPT->ShowDetails();

118
gpt.cc
View File

@@ -173,12 +173,11 @@ int GPTData::Verify(void) {
<< 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)) {
if ((mainHeader.diskGUID != secondHeader.diskGUID)) {
problems++;
cout << "\nProblem: main header's disk GUID (" << GUIDToStr(mainHeader.diskGUID)
cout << "\nProblem: main header's disk GUID (" << mainHeader.diskGUID.AsString()
<< ") doesn't\nmatch the backup GPT header's disk GUID ("
<< GUIDToStr(secondHeader.diskGUID) << ")\n"
<< secondHeader.diskGUID.AsString() << ")\n"
<< "You should use the 'b' or 'd' option on the recovery & transformation menu to\n"
<< "select one or the other header.\n";
} // if
@@ -368,8 +367,9 @@ int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
return (oldCRC == newCRC);
} // GPTData::CheckHeaderCRC()
// Recompute all the CRCs. Must be called before saving (but after reversing
// byte order on big-endian systems) if any changes have been made.
// Recompute all the CRCs. Must be called before saving if any changes have
// been made. Must be called on platform-ordered data (this function reverses
// byte order and then undoes that reversal.)
void GPTData::RecomputeCRCs(void) {
uint32_t crc, hSize, trueNumParts;
int littleEndian = 1;
@@ -377,13 +377,21 @@ void GPTData::RecomputeCRCs(void) {
// Initialize CRC functions...
chksum_crc32gentab();
// Save some key data from header before reversing byte order....
trueNumParts = mainHeader.numParts;
hSize = mainHeader.headerSize;
littleEndian = IsLittleEndian();
if ((littleEndian = IsLittleEndian()) == 0) {
ReversePartitionBytes();
ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
} // if
/* if ((littleEndian = IsLittleEndian()) == 0) {
ReverseBytes(&trueNumParts, 4);
ReverseBytes(&hSize, 4);
} // if */
// Compute CRC of partition tables & store in main and secondary headers
trueNumParts = mainHeader.numParts;
if (littleEndian == 0)
ReverseBytes(&trueNumParts, 4); // unreverse this key piece of data....
crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
mainHeader.partitionEntriesCRC = crc;
secondHeader.partitionEntriesCRC = crc;
@@ -405,6 +413,12 @@ void GPTData::RecomputeCRCs(void) {
if (littleEndian == 0)
ReverseBytes(&crc, 4);
secondHeader.headerCRC = crc;
if ((littleEndian = IsLittleEndian()) == 0) {
ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
ReversePartitionBytes();
} // if
} // GPTData::RecomputeCRCs()
// Rebuild the main GPT header, using the secondary header as a model.
@@ -421,8 +435,7 @@ void GPTData::RebuildMainHeader(void) {
mainHeader.backupLBA = secondHeader.currentLBA;
mainHeader.firstUsableLBA = secondHeader.firstUsableLBA;
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA;
mainHeader.diskGUID.data1 = secondHeader.diskGUID.data1;
mainHeader.diskGUID.data2 = secondHeader.diskGUID.data2;
mainHeader.diskGUID = secondHeader.diskGUID;
mainHeader.partitionEntriesLBA = UINT64_C(2);
mainHeader.numParts = secondHeader.numParts;
mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries;
@@ -445,8 +458,7 @@ void GPTData::RebuildSecondHeader(void) {
secondHeader.backupLBA = mainHeader.currentLBA;
secondHeader.firstUsableLBA = mainHeader.firstUsableLBA;
secondHeader.lastUsableLBA = mainHeader.lastUsableLBA;
secondHeader.diskGUID.data1 = mainHeader.diskGUID.data1;
secondHeader.diskGUID.data2 = mainHeader.diskGUID.data2;
secondHeader.diskGUID = mainHeader.diskGUID;
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
secondHeader.numParts = mainHeader.numParts;
secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries;
@@ -836,12 +848,14 @@ int GPTData::LoadSecondTableAsMain(void) {
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
// write, 0 if there was a problem.
int GPTData::SaveGPTData(int quiet) {
int allOK = 1;
int allOK = 1, littleEndian;
char answer;
uint64_t secondTable;
uint32_t numParts;
uint64_t offset;
littleEndian = IsLittleEndian();
if (device == "") {
cerr << "Device not defined.\n";
} // if
@@ -894,14 +908,17 @@ int GPTData::SaveGPTData(int quiet) {
// big-endian systems....
numParts = mainHeader.numParts;
secondTable = secondHeader.partitionEntriesLBA;
if (IsLittleEndian() == 0) {
/* if (IsLittleEndian() == 0) {
// Reverse partition bytes first, since that function requires non-reversed
// data from the main header....
ReversePartitionBytes();
ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
} // if
} // if */
RecomputeCRCs();
/* ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
ReversePartitionBytes(); */
if ((allOK) && (!quiet)) {
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"
@@ -922,16 +939,24 @@ int GPTData::SaveGPTData(int quiet) {
if (allOK && myDisk.OpenForWrite(device)) {
// Now write the main GPT header...
if (myDisk.Seek(1) == 1) {
if (!littleEndian)
ReverseHeaderBytes(&mainHeader);
if (myDisk.Write(&mainHeader, 512) != 512)
allOK = 0;
if (!littleEndian)
ReverseHeaderBytes(&mainHeader);
} else allOK = 0; // if (myDisk.Seek()...)
// Now write the main partition tables...
if (allOK) {
offset = mainHeader.partitionEntriesLBA;
if (myDisk.Seek(offset)) {
if (!littleEndian)
ReversePartitionBytes();
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0;
if (!littleEndian)
ReversePartitionBytes();
} else allOK = 0; // if (myDisk.Seek()...)
} // if (allOK)
@@ -947,18 +972,26 @@ int GPTData::SaveGPTData(int quiet) {
// Now write the secondary partition tables....
if (allOK) {
if (!littleEndian)
ReversePartitionBytes();
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0;
} // if (allOK)
if (!littleEndian)
ReversePartitionBytes();
} // if (allOK)
// Now write the secondary GPT header...
if (allOK) {
offset = mainHeader.backupLBA;
if (myDisk.Seek(offset)) {
if (!littleEndian)
ReverseHeaderBytes(&secondHeader);
if (myDisk.Seek(offset)) {
if (myDisk.Write(&secondHeader, 512) == -1)
allOK = 0;
} else allOK = 0; // if (myDisk.Seek()...)
} // if (allOK)
if (!littleEndian)
ReverseHeaderBytes(&secondHeader);
} // if (allOK)
// re-read the partition table
if (allOK) {
@@ -982,13 +1015,13 @@ int GPTData::SaveGPTData(int quiet) {
cout << "Aborting write of new partition table.\n";
} // if
if (IsLittleEndian() == 0) {
/* if (IsLittleEndian() == 0) {
// Reverse (normalize) header bytes first, since ReversePartitionBytes()
// requires non-reversed data in mainHeader...
ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
ReversePartitionBytes();
} // if
} // if */
return (allOK);
} // GPTData::SaveGPTData()
@@ -1005,6 +1038,12 @@ int GPTData::SaveGPTBackup(const string & filename) {
DiskIO backupFile;
if (backupFile.OpenForWrite(filename)) {
// Recomputing the CRCs is likely to alter them, which could be bad
// if the intent is to save a potentially bad GPT for later analysis;
// but if we don't do this, we get bogus errors when we load the
// backup. I'm favoring misses over false alarms....
RecomputeCRCs();
// Reverse the byte order, if necessary....
numParts = mainHeader.numParts;
if (IsLittleEndian() == 0) {
@@ -1013,12 +1052,6 @@ int GPTData::SaveGPTBackup(const string & filename) {
ReverseHeaderBytes(&secondHeader);
} // if
// Recomputing the CRCs is likely to alter them, which could be bad
// if the intent is to save a potentially bad GPT for later analysis;
// but if we don't do this, we get bogus errors when we load the
// backup. I'm favoring misses over false alarms....
RecomputeCRCs();
// Now write the protective MBR...
protectiveMBR.WriteMBRData(&backupFile);
@@ -1191,7 +1224,7 @@ void GPTData::DisplayGPTData(void) {
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 << "Disk identifier (GUID): " << mainHeader.diskGUID.AsString() << "\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";
@@ -1320,7 +1353,7 @@ void GPTData::CreatePartition(void) {
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
partitions[partNum].ChangeType();
partitions[partNum].SetName(partitions[partNum].GetNameType());
partitions[partNum].SetDefaultDescription();
} else {
cout << "No free sectors available\n";
} // if/else
@@ -1551,7 +1584,6 @@ WhichToUse GPTData::UseWhichPartitions(void) {
int GPTData::XFormPartitions(void) {
int i, numToConvert;
uint8_t origType;
struct newGUID;
// Clear out old data & prepare basics....
ClearGPTData();
@@ -1567,7 +1599,7 @@ int GPTData::XFormPartitions(void) {
// don't waste CPU time trying to convert extended, hybrid protective, or
// null (non-existent) partitions
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
(origType != 0x00) && (origType != 0xEE))
(origType != 0x00) && (origType != 0xEE))
partitions[i] = protectiveMBR.AsGPT(i);
} // for
@@ -1583,6 +1615,7 @@ int GPTData::XFormPartitions(void) {
// Transforms BSD disklabel on the specified partition (numbered from 0).
// If an invalid partition number is given, the program prompts for one.
// (Default for i is -1; called without an option, it therefore prompts.)
// Returns the number of new partitions created.
int GPTData::XFormDisklabel(int i) {
uint32_t low, high, partNum, startPart;
@@ -1635,7 +1668,7 @@ int GPTData::XFormDisklabel(BSDData* disklabel, uint32_t startPart) {
int i, numDone = 0;
if ((disklabel->IsDisklabel()) && (startPart >= 0) &&
(startPart < mainHeader.numParts)) {
(startPart < mainHeader.numParts)) {
for (i = 0; i < disklabel->GetNumParts(); i++) {
partitions[i + startPart] = disklabel->AsGPT(i);
if (partitions[i + startPart].GetFirstLBA() != UINT64_C(0))
@@ -1682,7 +1715,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
do {
cout << "Enter an MBR hex code (default " << hex;
cout.width(2);
cout << typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256 << "): ";
cout << partitions[gptPart].GetHexType() / 0x0100 << "): ";
junk = fgets(line, 255, stdin);
if (line[0] == '\n')
typeCode = partitions[gptPart].GetHexType() / 256;
@@ -1948,7 +1981,7 @@ uint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64
partitions[partNum].SetFirstLBA(startSector);
partitions[partNum].SetLastLBA(endSector);
partitions[partNum].SetType(0x0700);
partitions[partNum].SetUniqueGUID(1);
partitions[partNum].RandomizeUniqueGUID();
} else retval = 0; // if free space until endSector
} else retval = 0; // if startSector is free
} else retval = 0; // if legal partition number
@@ -2021,9 +2054,7 @@ int GPTData::ClearGPTData(void) {
mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA;
// Set a unique GUID for the disk, based on random numbers
// rand() is only 32 bits, so multiply together to fill a 64-bit value
mainHeader.diskGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
mainHeader.diskGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
mainHeader.diskGUID.Randomize();
// Copy main header to backup header
RebuildSecondHeader();
@@ -2392,8 +2423,7 @@ void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
ReverseBytes(&header->sizeOfPartitionEntries, 4);
ReverseBytes(&header->partitionEntriesCRC, 4);
ReverseBytes(&header->reserved2, GPT_RESERVED);
ReverseBytes(&header->diskGUID.data1, 8);
ReverseBytes(&header->diskGUID.data2, 8);
// header->diskGUID.ReverseGUIDBytes();
} // GPTData::ReverseHeaderBytes()
// IMPORTANT NOTE: This function requires non-reversed mainHeader
@@ -2458,6 +2488,14 @@ int SizesOK(void) {
cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n";
allOK = 0;
} // if
if (sizeof(GUIDData) != 16) {
cerr << "GUIDData is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n";
allOK = 0;
} // if
if (sizeof(PartType) != 16) {
cerr << "PartType is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n";
allOK = 0;
} // if
// Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware
if (IsLittleEndian() == 0) {
cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"

5
gpt.h
View File

@@ -16,7 +16,7 @@
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
#define GPTFDISK_VERSION "0.6.2"
#define GPTFDISK_VERSION "0.6.3"
using namespace std;
@@ -44,7 +44,7 @@ struct GPTHeader {
uint64_t backupLBA;
uint64_t firstUsableLBA;
uint64_t lastUsableLBA;
struct GUIDData diskGUID;
GUIDData diskGUID;
uint64_t partitionEntriesLBA;
uint32_t numParts;
uint32_t sizeOfPartitionEntries;
@@ -72,7 +72,6 @@ protected:
int apmFound; // set to 1 if APM detected
int bsdFound; // set to 1 if BSD disklabel detected in MBR
int sectorAlignment; // Start & end partitions at multiples of sectorAlignment
PartTypes typeHelper;
int beQuiet;
WhichToUse whichWasUsed;
public:

View File

@@ -23,8 +23,6 @@
using namespace std;
PartTypes GPTPart::typeHelper;
GPTPart::GPTPart(void) {
int i;
@@ -37,13 +35,13 @@ GPTPart::~GPTPart(void) {
// Return the gdisk-specific two-byte hex code for the partition
uint16_t GPTPart::GetHexType(void) {
return typeHelper.GUIDToID(partitionType);
return partitionType.GetHexType();
} // GPTPart::GetHexType()
// Return a plain-text description of the partition type (e.g., "Linux/Windows
// data" or "Linux swap").
string GPTPart::GetNameType(void) {
return typeHelper.GUIDToName(partitionType);
string GPTPart::GetTypeName(void) {
return partitionType.TypeName();
} // GPTPart::GetNameType()
// Compute and return the partition's length (or 0 if the end is incorrectly
@@ -56,7 +54,7 @@ uint64_t GPTPart::GetLengthLBA(void) {
} // GPTPart::GetLengthLBA()
// Return partition's name field, converted to a C++ ASCII string
string GPTPart::GetName(void) {
string GPTPart::GetDescription(void) {
string theName;
int i;
@@ -66,32 +64,18 @@ string GPTPart::GetName(void) {
theName += name[i];
} // for
return theName;
} // GPTPart::GetName()
} // GPTPart::GetDescription()
// 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) {
if (GetName() == typeHelper.GUIDToName(partitionType)) {
SetName(typeHelper.GUIDToName(t));
void GPTPart::SetType(PartType t) {
if (GetDescription() == partitionType.TypeName()) {
SetName(t.TypeName());
} // 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
void GPTPart::SetUniqueGUID(int zeroOrRandom) {
if (zeroOrRandom == 0) {
uniqueGUID.data1 = 0;
uniqueGUID.data2 = 0;
} else {
// rand() is only 32 bits on 32-bit systems, so multiply together to
// fill a 64-bit value.
uniqueGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
uniqueGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
}
} // GPTPart::SetUniqueGUID()
// 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
@@ -111,8 +95,9 @@ void GPTPart::SetName(const string & theName) {
// Input is likely to include a newline, so remove it....
i = strlen(newName);
if (newName[i - 1] == '\n')
newName[i - 1] = '\0';
if ((i > 0) && (i <= NAME_SIZE))
if (newName[i - 1] == '\n')
newName[i - 1] = '\0';
} else {
strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str());
} // if
@@ -128,6 +113,12 @@ void GPTPart::SetName(const string & theName) {
} // for
} // GPTPart::SetName()
// Set the name for the partition based on the current GUID partition type
// code's associated name
void GPTPart::SetDefaultDescription(void) {
SetName(partitionType.TypeName());
} // GPTPart::SetDefaultDescription()
GPTPart & GPTPart::operator=(const GPTPart & orig) {
int i;
@@ -159,10 +150,9 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
cout.fill('0');
cout.width(4);
cout.setf(ios::uppercase);
cout << hex << typeHelper.GUIDToID(partitionType) << " " << dec;
cout << hex << partitionType.GetHexType() << " " << dec;
cout.fill(' ');
// cout.setf(ios::right);
cout << GetName().substr(0, 23) << "\n";
cout << GetDescription().substr(0, 23) << "\n";
cout.fill(' ');
} // if
} // GPTPart::ShowSummary()
@@ -173,9 +163,9 @@ 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 << "Partition GUID code: " << partitionType.AsString();
cout << " (" << partitionType.TypeName() << ")\n";
cout << "Partition unique GUID: " << uniqueGUID.AsString() << "\n";
cout << "First sector: " << firstLBA << " (at "
<< BytesToSI(firstLBA * blockSize) << ")\n";
@@ -190,7 +180,7 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
cout << hex;
cout << attributes << "\n";
cout << dec;
cout << "Partition name: " << GetName() << "\n";
cout << "Partition name: " << GetDescription() << "\n";
cout.fill(' ');
} // if
} // GPTPart::ShowDetails()
@@ -198,12 +188,9 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
// Blank (delete) a single partition
void GPTPart::BlankPartition(void) {
int j;
GUIDData zeroGUID;
zeroGUID.data1 = 0;
zeroGUID.data2 = 0;
uniqueGUID = zeroGUID;
partitionType = zeroGUID;
uniqueGUID.Zero();
partitionType.Zero();
firstLBA = 0;
lastLBA = 0;
attributes = 0;
@@ -228,10 +215,8 @@ int GPTPart::DoTheyOverlap(const GPTPart & other) {
// 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);
// partitionType.ReverseGUIDBytes();
// uniqueGUID.ReverseGUIDBytes();
ReverseBytes(&firstLBA, 8);
ReverseBytes(&lastLBA, 8);
ReverseBytes(&attributes, 8);
@@ -241,30 +226,34 @@ void GPTPart::ReversePartBytes(void) {
* Functions requiring user interaction *
****************************************/
// Change the type code on the partition.
// Change the type code on the partition. Also changes the name if the original
// name is the generic one for the partition type.
void GPTPart::ChangeType(void) {
char line[255];
char* junk;
int typeNum = 0xFFFF;
GUIDData newType;
unsigned int typeNum = 0xFFFF, changeName = 0;
cout << "Current type is '" << GetNameType() << "'\n";
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
if (GetDescription() == GetTypeName())
changeName = 1;
cout << "Current type is '" << GetTypeName() << "'\n";
while ((!partitionType.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();
partitionType.ShowAllTypes();
if (line[0] == '\n') {
typeNum = 0x0700;
} // if
} // while
if (typeNum != 0) // user entered a code, so convert it
newType = typeHelper.IDToGUID((uint16_t) typeNum);
partitionType = 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";
partitionType.GetGUIDFromUser();
cout << "Changed type of partition to '" << partitionType.TypeName() << "'\n";
if (changeName) {
SetDefaultDescription();
} // if
} // GPTPart::ChangeType()
/***********************************

View File

@@ -20,6 +20,7 @@
#include <sys/types.h>
#include "support.h"
#include "parttypes.h"
#include "guid.h"
using namespace std;
@@ -38,38 +39,37 @@ class GPTPart {
// adjusting the data-load operation in GPTData::LoadMainTable() and
// GPTData::LoadSecondTableAsMain() and then removing the GPTPart
// size check in SizesOK() (in gpt.cc file).
struct GUIDData partitionType;
struct GUIDData uniqueGUID;
PartType partitionType;
GUIDData uniqueGUID;
uint64_t firstLBA;
uint64_t lastLBA;
uint64_t attributes;
unsigned char name[NAME_SIZE];
static PartTypes typeHelper;
public:
GPTPart(void);
~GPTPart(void);
// Simple data retrieval:
struct GUIDData GetType(void) {return partitionType;}
PartType & GetType(void) {return partitionType;}
uint16_t GetHexType(void);
string GetNameType(void);
struct GUIDData GetUniqueGUID(void) {return uniqueGUID;}
string GetTypeName(void);
GUIDData GetUniqueGUID(void) {return uniqueGUID;}
uint64_t GetFirstLBA(void) {return firstLBA;}
uint64_t GetLastLBA(void) {return lastLBA;}
uint64_t GetLengthLBA(void);
uint64_t GetAttributes(void) {return attributes;}
string GetName(void);
string GetDescription(void);
// Simple data assignment:
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 SetType(PartType t);
void SetType(uint16_t hex) {partitionType = hex;}
void SetUniqueGUID(GUIDData u) {uniqueGUID = u;}
void RandomizeUniqueGUID(void) {uniqueGUID.Randomize();}
void SetFirstLBA(uint64_t f) {firstLBA = f;}
void SetLastLBA(uint64_t l) {lastLBA = l;}
void SetAttributes(uint64_t a) {attributes = a;}
void SetName(const string & n);
void SetDefaultDescription(void);
// Additional functions
GPTPart & operator=(const GPTPart & orig);

20
mbr.cc
View File

@@ -39,6 +39,7 @@ MBRData::MBRData(void) {
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL;
canDeleteMyDisk = 0;
EmptyMBR();
} // MBRData default constructor
@@ -50,6 +51,7 @@ MBRData::MBRData(string filename) {
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL;
canDeleteMyDisk = 0;
srand((unsigned int) time(NULL));
// Try to read the specified partition table, but if it fails....
@@ -59,8 +61,12 @@ MBRData::MBRData(string filename) {
} // if
} // MBRData(string filename) constructor
// Free space used by myDisk only if that's OK -- sometimes it will be
// copied from an outside source, in which case that source should handle
// it!
MBRData::~MBRData(void) {
// delete myDisk;
if (canDeleteMyDisk)
delete myDisk;
} // MBRData destructor
/**********************
@@ -74,8 +80,10 @@ MBRData::~MBRData(void) {
int MBRData::ReadMBRData(const string & deviceFilename) {
int allOK = 1;
if (myDisk == NULL)
if (myDisk == NULL) {
myDisk = new DiskIO;
canDeleteMyDisk = 1;
} // if
if (myDisk->OpenForRead(deviceFilename)) {
ReadMBRData(myDisk);
} else {
@@ -98,8 +106,10 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
int err = 1;
TempMBR tempMBR;
if (myDisk != NULL)
if ((myDisk != NULL) && (canDeleteMyDisk)) {
delete myDisk;
canDeleteMyDisk = 0;
} // if
myDisk = theDisk;
@@ -831,9 +841,9 @@ GPTPart MBRData::AsGPT(int i) {
if (lastSector > 0) lastSector--;
newPart.SetLastLBA(lastSector);
newPart.SetType(((uint16_t) origType) * 0x0100);
newPart.SetUniqueGUID(1);
newPart.RandomizeUniqueGUID();
newPart.SetAttributes(0);
newPart.SetName(newPart.GetNameType());
newPart.SetName(newPart.GetTypeName());
} // if not extended, protective, or non-existent
} // if (origPart != NULL)
return newPart;

1
mbr.h
View File

@@ -71,6 +71,7 @@ protected:
uint64_t numHeads; // number of heads, in CHS scheme
uint64_t numSecspTrack; // number of sectors per track, in CHS scheme
DiskIO* myDisk;
int canDeleteMyDisk;
string device;
MBRValidity state;
struct MBRRecord* GetPartition(int i); // Return primary or logical partition

View File

@@ -16,9 +16,9 @@
using namespace std;
int PartTypes::numInstances = 0;
AType* PartTypes::allTypes = NULL;
AType* PartTypes::lastType = NULL;
int PartType::numInstances = 0;
AType* PartType::allTypes = NULL;
AType* PartType::lastType = NULL;
// Constructor. Its main task is to initialize the data list, but only
// if this is the first instance, since it's a static linked list.
@@ -31,166 +31,28 @@ AType* PartTypes::lastType = NULL;
// by typing "L" at the main gdisk menu.
// See http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
// for a list of MBR partition type codes.
PartTypes::PartTypes(void) {
PartType::PartType(void) : GUIDData() {
numInstances++;
if (numInstances == 1) {
// Start with the "unused entry," which should normally appear only
// on empty partition table entries....
AddType(0x0000, UINT64_C(0x0000000000000000), UINT64_C(0x0000000000000000),
"Unused entry", 0);
// DOS/Windows partition types, which confusingly Linux also uses in GPT
AddType(0x0100, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // FAT-12
AddType(0x0400, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // FAT-16 < 32M
AddType(0x0600, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // FAT-16
AddType(0x0700, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 1); // NTFS (or could be HPFS)
AddType(0x0b00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // FAT-32
AddType(0x0c00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // FAT-32 LBA
AddType(0x0c01, UINT64_C(0x4DB80B5CE3C9E316), UINT64_C(0xAE1502F02DF97D81),
"Microsoft Reserved"); // Microsoft reserved
AddType(0x0e00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // FAT-16 LBA
AddType(0x1100, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Hidden FAT-12
AddType(0x1400, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Hidden FAT-16 < 32M
AddType(0x1600, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Hidden FAT-16
AddType(0x1700, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Hidden NTFS (or could be HPFS)
AddType(0x1b00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Hidden FAT-32
AddType(0x1c00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Hidden FAT-32 LBA
AddType(0x1e00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Hidden FAT-16 LBA
AddType(0x2700, UINT64_C(0x4D4006D1DE94BBA4), UINT64_C(0xACD67901D5BF6AA1),
"Windows RE"); // Windows RE
AddType(0x4200, UINT64_C(0x4F621431Af9B60A0), UINT64_C(0xAD694A71113368BC),
"Windows LDM data"); // Logical disk manager
AddType(0x4201, UINT64_C(0x42E07E8F5808C8AA), UINT64_C(0xB3CF3404E9E1D285),
"Windows LDM metadata"); // Logical disk manager
// Linux-specific partition types....
AddType(0x8200, UINT64_C(0x43C4A4AB0657FD6D), UINT64_C(0x4F4F4BC83309E584),
"Linux swap"); // Linux swap (or could be Solaris)
AddType(0x8300, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
"Linux/Windows data", 0); // Linux native
AddType(0x8301, UINT64_C(0x60C000078DA63339), UINT64_C(0x080923C83A0836C4),
"Linux Reserved"); // Linux reserved
AddType(0x8e00, UINT64_C(0x44C2F507E6D6D379), UINT64_C(0x28F93D2A8F233CA2),
"Linux LVM"); // Linux LVM
// FreeBSD partition types....
// Note: Rather than extract FreeBSD disklabel data, convert FreeBSD
// partitions in-place, and let FreeBSD sort out the details....
AddType(0xa500, UINT64_C(0x11D66ECF516E7CB4), UINT64_C(0x2B71092D0200F88F),
"FreeBSD disklabel"); // FreeBSD disklabel
AddType(0xa501, UINT64_C(0x11DC7F4183BD6B9D), UINT64_C(0x0F4FB86015000BBE),
"FreeBSD boot"); // FreeBSD boot
AddType(0xa502, UINT64_C(0x11D66ECF516E7CB5), UINT64_C(0x2B71092D0200F88F),
"FreeBSD swap"); // FreeBSD swap
AddType(0xa503, UINT64_C(0x11D66ECF516E7CB6), UINT64_C(0x2B71092D0200F88F),
"FreeBSD UFS"); // FreeBSD UFS
AddType(0xa504, UINT64_C(0x11D66ECF516E7CBA), UINT64_C(0x2B71092D0200F88F),
"FreeBSD ZFS"); // FreeBSD ZFS
AddType(0xa505, UINT64_C(0x11D66ECF516E7CB8), UINT64_C(0x2B71092D0200F88F),
"FreeBSD Vinum/RAID"); // FreeBSD Vinum
// A MacOS partition type, separated from others by NetBSD partition types...
AddType(0xa800, UINT64_C(0x11AA000055465300), UINT64_C(0xACEC4365300011AA),
"Apple UFS"); // MacOS X
// NetBSD partition types. Note that the main entry sets it up as a
// FreeBSD disklabel. I'm not 100% certain this is the correct behavior.
AddType(0xa900, UINT64_C(0x11D66ECF516E7CB4), UINT64_C(0x2B71092D0200F88F),
"FreeBSD disklabel", 0); // NetBSD disklabel
AddType(0xa901, UINT64_C(0x11DCB10E49F48D32), UINT64_C(0x489687D119009BB9),
"NetBSD swap");
AddType(0xa902, UINT64_C(0x11DCB10E49F48D5A), UINT64_C(0x489687D119009BB9),
"NetBSD FFS");
AddType(0xa903, UINT64_C(0x11DCB10E49F48D82), UINT64_C(0x489687D119009BB9),
"NetBSD LFS");
AddType(0xa903, UINT64_C(0x11DCB10E49F48DAA), UINT64_C(0x489687D119009BB9),
"NetBSD RAID");
AddType(0xa904, UINT64_C(0x11DCB10F2DB519C4), UINT64_C(0x489687D119009BB9),
"NetBSD concatenated");
AddType(0xa905, UINT64_C(0x11DCB10F2DB519EC), UINT64_C(0x489687D119009BB9),
"NetBSD encrypted");
// MacOS partition types (See also 0xa800, above)....
AddType(0xab00, UINT64_C(0x11AA0000426F6F74), UINT64_C(0xACEC4365300011AA),
"Apple boot"); // MacOS X
AddType(0xaf00, UINT64_C(0x11AA000048465300), UINT64_C(0xACEC4365300011AA),
"Apple HFS/HFS+"); // MacOS X
AddType(0xaf01, UINT64_C(0x11AA000052414944), UINT64_C(0xACEC4365300011AA),
"Apple RAID"); // MacOS X
AddType(0xaf02, UINT64_C(0x11AA5F4F52414944), UINT64_C(0xACEC4365300011AA),
"Apple RAID offline"); // MacOS X
AddType(0xaf03, UINT64_C(0x11AA6C004C616265), UINT64_C(0xACEC4365300011AA),
"Apple label"); // MacOS X
AddType(0xaf04, UINT64_C(0x11AA76655265636F), UINT64_C(0xACEC4365300011AA),
"AppleTV recovery"); // MacOS X
// Solaris partition types (one of which is shared with MacOS)
AddType(0xbe00, UINT64_C(0x11B21DD26A82CB45), UINT64_C(0x316673200008A699),
"Solaris boot"); // Solaris boot
AddType(0xbf00, UINT64_C(0x11B21DD26a85CF4D), UINT64_C(0x316673200008A699),
"Solaris root"); // Solaris root
AddType(0xbf01, UINT64_C(0x11B21DD26A898CC3), UINT64_C(0x316673200008A699),
"Solaris /usr & Mac ZFS"); // MacOS X & Solaris
AddType(0xbf02, UINT64_C(0x11B21DD26A87C46F), UINT64_C(0x316673200008A699),
"Solaris swap");
AddType(0xbf03, UINT64_C(0x11B21DD26A8B642B), UINT64_C(0x316673200008A699),
"Solaris backup");
AddType(0xbf04, UINT64_C(0x11B21DD26A8EF2E9), UINT64_C(0x316673200008A699),
"Solaris /var");
AddType(0xbf05, UINT64_C(0x11B21DD26A90BA39), UINT64_C(0x316673200008A699),
"Solaris /home");
AddType(0xbf05, UINT64_C(0x11B21DD26A9283A5), UINT64_C(0x316673200008A699),
"Solaris EFI_ALTSCTR");
AddType(0xbf06, UINT64_C(0x11B21DD26A945A3B), UINT64_C(0x316673200008A699),
"Solaris Reserved 1");
AddType(0xbf07, UINT64_C(0x11B21DD26A9630D1), UINT64_C(0x316673200008A699),
"Solaris Reserved 2");
AddType(0xbf08, UINT64_C(0x11B21DD26A980767), UINT64_C(0x316673200008A699),
"Solaris Reserved 3");
AddType(0xbf09, UINT64_C(0x11B21DD26A96237F), UINT64_C(0x316673200008A699),
"Solaris Reserved 4");
AddType(0xbf0a, UINT64_C(0x11B21DD26A8D2AC7), UINT64_C(0x316673200008A699),
"Solaris Reserved 5");
// I can find no MBR equivalents for these, but they're on the
// Wikipedia page for GPT, so here we go....
AddType(0xc001, UINT64_C(0x11D33AEB75894C1E), UINT64_C(0x000000A0037BC1B7),
"HP-UX data");
AddType(0xc002, UINT64_C(0x11D632E3E2A1E728), UINT64_C(0x000000A0037B82A6),
"HP-UX service");
// EFI system and related partitions
AddType(0xEF00, UINT64_C(0x11d2f81fc12a7328), UINT64_C(0x3bc93ec9a0004bba),
"EFI System"); // EFI System (parted marks Linux boot
// partitions like this)
AddType(0xEF01, UINT64_C(0x11d333e7024dee41), UINT64_C(0x9FF381C70800699d),
"MBR partition scheme"); // Used to nest an MBR table on a GPT disk
AddType(0xEF02, UINT64_C(0x6E6F644921686148), UINT64_C(0x4946456465654E74),
"BIOS boot partition"); //
// A straggler Linux partition type....
AddType(0xfd00, UINT64_C(0x4D3B05FCA19D880F), UINT64_C(0x1E91840F3F7406A0),
"Linux RAID"); // Linux RAID
AddAllTypes();
} // if
} // default constructor
PartTypes::~PartTypes(void) {
PartType::PartType(const PartType & orig) : GUIDData(orig) {
numInstances++;
if (numInstances == 1) { // should never happen; just being paranoid
AddAllTypes();
} // if
} // PartType copy constructor
PartType::PartType(const GUIDData & orig) : GUIDData(orig) {
numInstances++;
if (numInstances == 1) {
AddAllTypes();
} // if
} // PartType copy constructor
PartType::~PartType(void) {
AType* tempType;
numInstances--;
@@ -203,19 +65,117 @@ PartTypes::~PartTypes(void) {
} // if
} // destructor
// Add all partition type codes to the internal linked-list structure.
// Used by constructors.
void PartType::AddAllTypes(void) {
// Start with the "unused entry," which should normally appear only
// on empty partition table entries....
AddType(0x0000, "00000000-0000-0000-0000-000000000000", "Unused entry", 0);
// DOS/Windows partition types, which confusingly Linux also uses in GPT
AddType(0x0100, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // FAT-12
AddType(0x0400, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // FAT-16 < 32M
AddType(0x0600, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // FAT-16
AddType(0x0700, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 1); // NTFS (or HPFS)
AddType(0x0b00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // FAT-32
AddType(0x0c00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // FAT-32 LBA
AddType(0x0c01, "E3C9E316-0B5C-4DB8-817D-F92DF00215AE", "Microsoft reserved");
AddType(0x0e00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // FAT-16 LBA
AddType(0x1100, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Hidden FAT-12
AddType(0x1400, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Hidden FAT-16 < 32M
AddType(0x1600, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Hidden FAT-16
AddType(0x1700, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Hidden NTFS (or HPFS)
AddType(0x1b00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Hidden FAT-32
AddType(0x1c00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Hidden FAT-32 LBA
AddType(0x1e00, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Hidden FAT-16 LBA
AddType(0x2700, "DE94BBA4-06D1-4D40-A16A-BFD50179D6AC", "Windows RE");
AddType(0x4200, "AF9B60A0-1431-4F62-BC68-3311714A69AD", "Windows LDM data"); // Logical disk manager
AddType(0x4201, "5808C8AA-7E8F-42E0-85D2-E1E90434CFB3", "Windows LDM metadata"); // Logical disk manager
// An oddball IBM filesystem....
AddType(0x7501, "37AFFC90-EF7D-4E96-91C3-2D7AE055B174", "IBM GPFS"); // General Parallel File System (GPFS)
// Linux-specific partition types....
AddType(0x8200, "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", "Linux swap"); // Linux swap (or Solaris)
AddType(0x8300, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Linux native
AddType(0x8301, "8DA63339-0007-60C0-C436-083AC8230908", "Linux reserved");
AddType(0x8e00, "E6D6D379-F507-44C2-A23C-238F2A3DF928", "Linux LVM");
// FreeBSD partition types....
// Note: Rather than extract FreeBSD disklabel data, convert FreeBSD
// partitions in-place, and let FreeBSD sort out the details....
AddType(0xa500, "516E7CB4-6ECF-11D6-8FF8-00022D09712B", "FreeBSD Disklabel");
AddType(0xa501, "83BD6B9D-7F41-11DC-BE0B-001560B84F0F", "FreeBSD boot");
AddType(0xa502, "516E7CB5-6ECF-11D6-8FF8-00022D09712B", "FreeBSD swap");
AddType(0xa503, "516E7CB6-6ECF-11D6-8FF8-00022D09712B", "FreeBSD UFS");
AddType(0xa504, "516E7CBA-6ECF-11D6-8FF8-00022D09712B", "FreeBSD ZFS");
AddType(0xa505, "516E7CB8-6ECF-11D6-8FF8-00022D09712B", "FreeBSD Vinum/RAID");
// A MacOS partition type, separated from others by NetBSD partition types...
AddType(0xa800, "55465300-0000-11AA-AA11-00306543ECAC", "Apple UFS"); // Mac OS X
// NetBSD partition types. Note that the main entry sets it up as a
// FreeBSD disklabel. I'm not 100% certain this is the correct behavior.
AddType(0xa900, "516E7CB4-6ECF-11D6-8FF8-00022D09712B", "FreeBSD disklabel", 0); // NetBSD disklabel
AddType(0xa901, "49F48D32-B10E-11DC-B99B-0019D1879648", "NetBSD swap");
AddType(0xa902, "49F48D5A-B10E-11DC-B99B-0019D1879648", "NetBSD FFS");
AddType(0xa903, "49F48D82-B10E-11DC-B99B-0019D1879648", "NetBSD LFS");
AddType(0xa904, "2DB519C4-B10F-11DC-B99B-0019D1879648", "NetBSD concatenated");
AddType(0xa905, "2DB519EC-B10F-11DC-B99B-0019D1879648", "NetBSD encrypted");
AddType(0xa906, "49F48DAA-B10E-11DC-B99B-0019D1879648", "NetBSD RAID");
// Mac OS partition types (See also 0xa800, above)....
AddType(0xab00, "426F6F74-0000-11AA-AA11-00306543ECAC", "Apple boot");
AddType(0xaf00, "48465300-0000-11AA-AA11-00306543ECAC", "Apple HFS/HFS+");
AddType(0xaf01, "52414944-0000-11AA-AA11-00306543ECAC", "Apple RAID");
AddType(0xaf02, "52414944-5F4F-11AA-AA11-00306543ECAC", "Apple RAID offline");
AddType(0xaf03, "4C616265-6C00-11AA-AA11-00306543ECAC", "Apple label");
AddType(0xaf04, "5265636F-7665-11AA-AA11-00306543ECAC", "AppleTV recovery");
// Solaris partition types (one of which is shared with MacOS)
AddType(0xbe00, "6A82CB45-1DD2-11B2-99A6-080020736631", "Solaris boot");
AddType(0xbf00, "6A85CF4D-1DD2-11B2-99A6-080020736631", "Solaris root");
AddType(0xbf01, "6A898CC3-1DD2-11B2-99A6-080020736631", "Solaris /usr & Mac ZFS"); // Solaris/MacOS
AddType(0xbf02, "6A87C46F-1DD2-11B2-99A6-080020736631", "Solaris swap");
AddType(0xbf03, "6A8B642B-1DD2-11B2-99A6-080020736631", "Solaris backup");
AddType(0xbf04, "6A8EF2E9-1DD2-11B2-99A6-080020736631", "Solaris /var");
AddType(0xbf05, "6A90BA39-1DD2-11B2-99A6-080020736631", "Solaris /home");
AddType(0xbf06, "6A9283A5-1DD2-11B2-99A6-080020736631", "Solaris alternate sector");
AddType(0xbf07, "6A945A3B-1DD2-11B2-99A6-080020736631", "Solaris Reserved 1");
AddType(0xbf08, "6A9630D1-1DD2-11B2-99A6-080020736631", "Solaris Reserved 2");
AddType(0xbf09, "6A980767-1DD2-11B2-99A6-080020736631", "Solaris Reserved 3");
AddType(0xbf0a, "6A96237F-1DD2-11B2-99A6-080020736631", "Solaris Reserved 4");
AddType(0xbf0b, "6A8D2AC7-1DD2-11B2-99A6-080020736631", "Solaris Reserved 5");
// I can find no MBR equivalents for these, but they're on the
// Wikipedia page for GPT, so here we go....
AddType(0xc001, "75894C1E-3AEB-11D3-B7C1-7B03A0000000", "HP-UX data");
AddType(0xc002, "E2A1E728-32E3-11D6-A682-7B03A0000000", "HP-UX service");
// EFI system and related partitions
AddType(0xef00, "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "EFI System"); // Parted marks Linux boot partitions as this
AddType(0xef01, "024DEE41-33E7-11D3-9D69-0008C781F39F", "MBR partition scheme"); // Used to nest MBR in GPT
AddType(0xef02, "21686148-6449-6E6F-744E-656564454649", "BIOS boot partition"); // Boot loader
// A straggler Linux partition type....
AddType(0xfd00, "A19D880F-05FC-4D3B-A006-743F0F84911E", "Linux RAID");
// Note: DO NOT use the 0xffff code; that's reserved to indicate an
// unknown type code.
} // PartType::AddAllTypes()
// Add a single type to the linked list of types. Returns 1 if operation
// succeeds, 0 otherwise.
int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
const char * n, int toDisplay) {
int PartType::AddType(uint16_t mbrType, const char * guidData, const char * name,
int toDisplay) {
AType* tempType;
int allOK = 1;
tempType = new AType;
if (tempType != NULL) {
tempType->MBRType = mbrType;
tempType->GUIDType.data1 = guidData1;
tempType->GUIDType.data2 = guidData2;
tempType->name = n;
tempType->GUIDType = guidData;
tempType->name = name;
tempType->display = toDisplay;
tempType->next = NULL;
if (allTypes == NULL) { // first entry
@@ -228,13 +188,85 @@ int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
allOK = 0;
} // if/else
return allOK;
} // PartTypes::AddType()
} // GUID::AddType(const char* variant)
// Assign a GUID based on my custom 2-byte (16-bit) MBR hex ID variant
GUIDData & PartType::operator=(uint16_t ID) {
AType* theItem = allTypes;
int found = 0;
// Assign a default value....
GUIDData::operator=("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); // 0700, Linux/Windows data
// Now search the type list for a match to the ID....
while ((theItem != NULL) && (!found)) {
if (theItem->MBRType == ID) { // found it!
GUIDData::operator=(theItem->GUIDType);
found = 1;
} else {
theItem = theItem->next;
} // if/else
} // while
if (!found) {
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;
cout.fill(' ');
} // if (!found)
return *this;
} // PartType::operator=(uint16_t ID)
// Return the English description of the partition type (e.g., "Linux/Windows data")
string PartType::TypeName(void) {
AType* theItem = allTypes;
int found = 0;
string typeName;
while ((theItem != NULL) && (!found)) {
if (theItem->GUIDType == *this) { // found it!
typeName = theItem->name;
found = 1;
} else {
theItem = theItem->next;
} // if/else
} // while
if (!found) {
typeName = "Unknown";
} // if (!found)
return typeName;
} // PartType::TypeName()
// Return the custom GPT fdisk 2-byte (16-bit) hex code for this GUID partition type
// Note that this function ignores entries for which the display variable
// is set to 0. This enables control of which values get returned when
// there are multiple possibilities, but opens the algorithm up to the
// potential for problems should the data in the list be bad.
uint16_t PartType::GetHexType() {
AType* theItem = allTypes;
int found = 0;
uint16_t theID = 0xFFFF;
while ((theItem != NULL) && (!found)) {
if ((theItem->GUIDType == *this) && (theItem->display == 1)) { // found it!
theID = theItem->MBRType;
found = 1;
} else {
theItem = theItem->next;
} // if/else
} // while
if (!found) {
theID = 0xFFFF;
} // if (!found)
return theID;
} // PartType::GetHex()
// Displays the available types and my extended MBR codes for same....
// Note: This function assumes an 80-column display. On wider displays,
// it stops at under 80 columns; on narrower displays, lines will wrap
// in an ugly way.
void PartTypes::ShowTypes(void) {
void PartType::ShowAllTypes(void) {
int colCount = 1; // column count
size_t i;
AType* thisType = allTypes;
@@ -257,10 +289,10 @@ void PartTypes::ShowTypes(void) {
} // while
cout.fill(' ');
cout << "\n" << dec;
} // PartTypes::ShowTypes()
} // PartType::ShowTypes()
// Returns 1 if code is a valid extended MBR code, 0 if it's not
int PartTypes::Valid(uint16_t code) {
int PartType::Valid(uint16_t code) {
AType* thisType = allTypes;
int found = 0;
@@ -271,85 +303,4 @@ int PartTypes::Valid(uint16_t code) {
thisType = thisType->next;
} // while
return found;
} // PartTypes::Valid()
// Convert a GUID code to a name.
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!
typeName = theItem->name;
found = 1;
} else {
theItem = theItem->next;
} // if/else
} // while
if (!found) {
typeName = "Unknown";
} // if (!found)
return typeName;
} // PartTypes::GUIDToName()
// This function takes a variant of the MBR partition type code and
// converts it to a GUID type code
struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
AType* theItem = allTypes;
int found = 0;
struct GUIDData theGUID;
// Start by assigning a default GUID for the return value. Done
// "raw" to avoid the necessity for a recursive call and the
// remote possibility of an infinite recursive loop that this
// approach would present....
theGUID.data1 = UINT64_C(0x4433B9E5EBD0A0A2);
theGUID.data2 = UINT64_C(0xC79926B7B668C087);
// Now search the type list for a match to the ID....
while ((theItem != NULL) && (!found)) {
if (theItem->MBRType == ID) { // found it!
theGUID = theItem->GUIDType;
found = 1;
} else {
theItem = theItem->next;
} // if/else
} // while
if (!found) {
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;
cout.fill(' ');
} // if (!found)
return theGUID;
} // PartTypes::IDToGUID()
// Convert a GUID to a 16-bit variant of the MBR ID number.
// Note that this function ignores entries for which the display variable
// is set to 0. This enables control of which values get returned when
// there are multiple possibilities, but opens the algorithm up to the
// potential for problems should the data in the list be bad.
uint16_t PartTypes::GUIDToID(struct GUIDData typeCode) {
AType* theItem = allTypes;
int found = 0;
uint16_t theID = 0xFFFF;
while ((theItem != NULL) && (!found)) {
if ((theItem->GUIDType.data1 == typeCode.data1) &&
(theItem->GUIDType.data2 == typeCode.data2) &&
(theItem->display == 1)) { // found it!
theID = theItem->MBRType;
found = 1;
} else {
theItem = theItem->next;
} // if/else
} // while
if (!found) {
theID = 0xFFFF;
} // if (!found)
return theID;
} // PartTypes::GUIDToID()
} // PartType::Valid()

View File

@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <string>
#include "support.h"
#include "guid.h"
#ifndef __PARTITION_TYPES
#define __PARTITION_TYPES
@@ -18,27 +19,42 @@ struct AType {
// type codes, so as to permit disambiguation and use of new
// codes required by GPT
uint16_t MBRType;
struct GUIDData GUIDType;
GUIDData GUIDType;
string name;
int display; // 1 to show to users as available type, 0 not to
AType* next;
}; // struct AType
class PartTypes {
class PartType : public GUIDData {
protected:
static int numInstances;
static AType* allTypes; // Linked list holding all the data
static AType* lastType; // Pointer to last entry in the list
void AddAllTypes(void);
public:
PartTypes(void);
~PartTypes(void);
int AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
const char * name, int toDisplay = 1);
void ShowTypes(void);
PartType(void);
PartType(const PartType & orig);
PartType(const GUIDData & orig);
~PartType(void);
// Set up type information
int AddType(uint16_t mbrType, const char * guidData, const char * name, int toDisplay = 1);
// Assignment operators based on base class....
GUIDData & operator=(const GUIDData & orig) {return GUIDData::operator=(orig);}
GUIDData & operator=(const string & orig) {return GUIDData::operator=(orig);}
GUIDData & operator=(const char * orig) {return GUIDData::operator=(orig);}
// New data assignment
GUIDData & operator=(uint16_t ID); // Use MBR type code time 0x0100 to assign GUID
// Retrieve transformed GUID data based on type code matches
string TypeName(void);
uint16_t GetHexType();
// Information relating to all type data
void ShowAllTypes(void);
int Valid(uint16_t);
string GUIDToName(struct GUIDData typeCode);
struct GUIDData IDToGUID(uint16_t ID);
uint16_t GUIDToID(struct GUIDData);
};
#endif

View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH "SGDISK" "8" "0.6.0" "Roderick W. Smith" "GPT fdisk Manual"
.TH "SGDISK" "8" "0.6.3" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS"

View File

@@ -37,7 +37,7 @@ int main(int argc, char *argv[]) {
char *device = NULL;
char *newPartInfo = NULL, *typeCode = NULL, *partName;
char *backupFile = NULL;
PartTypes typeHelper;
PartType typeHelper;
poptContext poptCon;
struct poptOption theOptions[] =
@@ -82,7 +82,7 @@ int main(int argc, char *argv[]) {
while ((opt = poptGetNextOpt(poptCon)) > 0) {
switch (opt) {
case 'L':
typeHelper.ShowTypes();
typeHelper.ShowAllTypes();
break;
case 'P':
pretend = 1;

View File

@@ -200,112 +200,19 @@ string BytesToSI(uint64_t size) {
return theValue;
} // BlocksToSI()
// Return a plain-text name for a partition type.
// Convert a GUID to a string representation, suitable for display
// to humans....
string GUIDToStr(struct GUIDData theGUID) {
unsigned long long blocks[11];
char theString[40];
// Converts two consecutive characters in the input string into a
// number, interpreting the string as a hexadecimal number, starting
// at the specified position.
unsigned char StrToHex(const string & input, unsigned int position) {
unsigned char retval = 0x00;
unsigned int temp;
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()
// Get a GUID from the user
GUIDData GetGUID(void) {
unsigned long long part1, part2, part3, part4, part5;
int entered = 0;
char temp[255], temp2[255];
char* junk;
GUIDData theGUID;
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....
if ((temp[0] == 'r') || (temp[0] == 'R')) {
theGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
theGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
entered = 1;
} // if user entered 'R' or 'r'
// If string length is right for whole entry, try to parse it....
if ((strlen(temp) == 37) && (entered == 0)) {
strncpy(temp2, &temp[0], 8);
temp2[8] = '\0';
sscanf(temp2, "%llx", &part1);
strncpy(temp2, &temp[9], 4);
temp2[4] = '\0';
sscanf(temp2, "%llx", &part2);
strncpy(temp2, &temp[14], 4);
temp2[4] = '\0';
sscanf(temp2, "%llx", &part3);
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
strncpy(temp2, &temp[19], 4);
temp2[4] = '\0';
sscanf(temp2, "%llx", &part4);
strncpy(temp2, &temp[24], 12);
temp2[12] = '\0';
sscanf(temp2, "%llx", &part5);
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
((part4 & UINT64_C(0x00000000000000FF)) << 8) +
((part5 & UINT64_C(0x0000FF0000000000)) >> 24) +
((part5 & UINT64_C(0x000000FF00000000)) >> 8) +
((part5 & UINT64_C(0x00000000FF000000)) << 8) +
((part5 & UINT64_C(0x0000000000FF0000)) << 24) +
((part5 & UINT64_C(0x000000000000FF00)) << 40) +
((part5 & UINT64_C(0x00000000000000FF)) << 56);
entered = 1;
if (input.length() >= (position + 2)) {
sscanf(input.substr(position, 2).c_str(), "%x", &temp);
retval = (unsigned char) temp;
} // if
// If neither of the above methods of entry was used, use prompted
// entry....
if (entered == 0) {
sscanf(temp, "%llx", &part1);
cout << "Enter a two-byte hexadecimal number for the second segment: ";
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part2);
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;
cout << "Enter a two-byte hexadecimal number for the fourth segment: ";
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part4);
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) +
((part4 & UINT64_C(0x00000000000000FF)) << 8) +
((part5 & UINT64_C(0x0000FF0000000000)) >> 24) +
((part5 & UINT64_C(0x000000FF00000000)) >> 8) +
((part5 & UINT64_C(0x00000000FF000000)) << 8) +
((part5 & UINT64_C(0x0000000000FF0000)) << 24) +
((part5 & UINT64_C(0x000000000000FF00)) << 40) +
((part5 & UINT64_C(0x00000000000000FF)) << 56);
entered = 1;
} // if/else
cout << "New GUID: " << GUIDToStr(theGUID) << "\n";
return theGUID;
} // GetGUID()
return retval;
} // StrToHex()
// Return 1 if the CPU architecture is little endian, 0 if it's big endian....
int IsLittleEndian(void) {

View File

@@ -23,11 +23,6 @@
#include <linux/fs.h>
#endif
/* #ifdef __FreeBSD__
#define fstat64 fstat
#define stat64 stat
#endif */
// Set this as a default
#define SECTOR_SIZE UINT32_C(512)
@@ -53,20 +48,11 @@
using namespace std;
// a GUID
struct GUIDData {
uint64_t data1;
uint64_t data2;
}; // struct GUIDData
// static char theFile[255];
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, const string & prompt);
string BytesToSI(uint64_t size);
string GUIDToStr(struct GUIDData theGUID);
GUIDData GetGUID(void);
unsigned char StrToHex(const string & input, unsigned int position);
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
uint64_t PowerOf2(int value);