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): 0.6.2 (1/29/2010):
------------------ ------------------

View File

@@ -2,7 +2,7 @@ CC=gcc
CXX=g++ CXX=g++
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -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 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_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o) LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h) LIB_HEADERS=$(LIB_NAMES:=.h)
@@ -11,10 +11,13 @@ DEPEND= makedepend $(CFLAGS)
all: gdisk sgdisk all: gdisk sgdisk
gdisk: $(LIB_OBJS) gdisk.o 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 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: #no pre-reqs
lint $(SRCS) lint $(SRCS)

View File

@@ -2,8 +2,9 @@ CC=/usr/bin/i586-mingw32msvc-gcc
CXX=/usr/bin/i586-mingw32msvc-g++ CXX=/usr/bin/i586-mingw32msvc-g++
STRIP=/usr/bin/i586-mingw32msvc-strip STRIP=/usr/bin/i586-mingw32msvc-strip
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -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 CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -g
LIB_NAMES=gptpart bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows #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_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o) LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h) LIB_HEADERS=$(LIB_NAMES:=.h)
@@ -12,10 +13,10 @@ DEPEND= makedepend $(CFLAGS)
all: gdisk all: gdisk
gdisk: $(LIB_OBJS) gdisk.o 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 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: #no pre-reqs
lint $(SRCS) lint $(SRCS)

35
README
View File

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

View File

@@ -30,7 +30,7 @@ Attributes::Attributes(void) {
} // for } // for
// Now reset those names that are defined.... // 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[60] = "read-only";
atNames[62] = "hidden"; atNames[62] = "hidden";
atNames[63] = "do not automount"; atNames[63] = "do not automount";

4
bsd.cc
View File

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

View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com) .\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License .\" 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" .SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS" .SH "SYNOPSIS"

View File

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

108
gpt.cc
View File

@@ -173,12 +173,11 @@ int GPTData::Verify(void) {
<< secondHeader.lastUsableLBA << ")\n" << secondHeader.lastUsableLBA << ")\n"
<< "The 'e' option on the experts' menu can probably fix this problem.\n"; << "The 'e' option on the experts' menu can probably fix this problem.\n";
} // if } // if
if ((mainHeader.diskGUID.data1 != secondHeader.diskGUID.data1) || if ((mainHeader.diskGUID != secondHeader.diskGUID)) {
(mainHeader.diskGUID.data2 != secondHeader.diskGUID.data2)) {
problems++; 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 (" << ") 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" << "You should use the 'b' or 'd' option on the recovery & transformation menu to\n"
<< "select one or the other header.\n"; << "select one or the other header.\n";
} // if } // if
@@ -368,8 +367,9 @@ int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
return (oldCRC == newCRC); return (oldCRC == newCRC);
} // GPTData::CheckHeaderCRC() } // GPTData::CheckHeaderCRC()
// Recompute all the CRCs. Must be called before saving (but after reversing // Recompute all the CRCs. Must be called before saving if any changes have
// byte order on big-endian systems) if any changes have been made. // been made. Must be called on platform-ordered data (this function reverses
// byte order and then undoes that reversal.)
void GPTData::RecomputeCRCs(void) { void GPTData::RecomputeCRCs(void) {
uint32_t crc, hSize, trueNumParts; uint32_t crc, hSize, trueNumParts;
int littleEndian = 1; int littleEndian = 1;
@@ -377,13 +377,21 @@ void GPTData::RecomputeCRCs(void) {
// Initialize CRC functions... // Initialize CRC functions...
chksum_crc32gentab(); chksum_crc32gentab();
// Save some key data from header before reversing byte order....
trueNumParts = mainHeader.numParts;
hSize = mainHeader.headerSize; 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 // 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); crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
mainHeader.partitionEntriesCRC = crc; mainHeader.partitionEntriesCRC = crc;
secondHeader.partitionEntriesCRC = crc; secondHeader.partitionEntriesCRC = crc;
@@ -405,6 +413,12 @@ void GPTData::RecomputeCRCs(void) {
if (littleEndian == 0) if (littleEndian == 0)
ReverseBytes(&crc, 4); ReverseBytes(&crc, 4);
secondHeader.headerCRC = crc; secondHeader.headerCRC = crc;
if ((littleEndian = IsLittleEndian()) == 0) {
ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
ReversePartitionBytes();
} // if
} // GPTData::RecomputeCRCs() } // GPTData::RecomputeCRCs()
// Rebuild the main GPT header, using the secondary header as a model. // 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.backupLBA = secondHeader.currentLBA;
mainHeader.firstUsableLBA = secondHeader.firstUsableLBA; mainHeader.firstUsableLBA = secondHeader.firstUsableLBA;
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA; mainHeader.lastUsableLBA = secondHeader.lastUsableLBA;
mainHeader.diskGUID.data1 = secondHeader.diskGUID.data1; mainHeader.diskGUID = secondHeader.diskGUID;
mainHeader.diskGUID.data2 = secondHeader.diskGUID.data2;
mainHeader.partitionEntriesLBA = UINT64_C(2); mainHeader.partitionEntriesLBA = UINT64_C(2);
mainHeader.numParts = secondHeader.numParts; mainHeader.numParts = secondHeader.numParts;
mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries; mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries;
@@ -445,8 +458,7 @@ void GPTData::RebuildSecondHeader(void) {
secondHeader.backupLBA = mainHeader.currentLBA; secondHeader.backupLBA = mainHeader.currentLBA;
secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; secondHeader.firstUsableLBA = mainHeader.firstUsableLBA;
secondHeader.lastUsableLBA = mainHeader.lastUsableLBA; secondHeader.lastUsableLBA = mainHeader.lastUsableLBA;
secondHeader.diskGUID.data1 = mainHeader.diskGUID.data1; secondHeader.diskGUID = mainHeader.diskGUID;
secondHeader.diskGUID.data2 = mainHeader.diskGUID.data2;
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
secondHeader.numParts = mainHeader.numParts; secondHeader.numParts = mainHeader.numParts;
secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries; secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries;
@@ -836,12 +848,14 @@ int GPTData::LoadSecondTableAsMain(void) {
// Writes GPT (and protective MBR) to disk. Returns 1 on successful // Writes GPT (and protective MBR) to disk. Returns 1 on successful
// write, 0 if there was a problem. // write, 0 if there was a problem.
int GPTData::SaveGPTData(int quiet) { int GPTData::SaveGPTData(int quiet) {
int allOK = 1; int allOK = 1, littleEndian;
char answer; char answer;
uint64_t secondTable; uint64_t secondTable;
uint32_t numParts; uint32_t numParts;
uint64_t offset; uint64_t offset;
littleEndian = IsLittleEndian();
if (device == "") { if (device == "") {
cerr << "Device not defined.\n"; cerr << "Device not defined.\n";
} // if } // if
@@ -894,14 +908,17 @@ int GPTData::SaveGPTData(int quiet) {
// big-endian systems.... // big-endian systems....
numParts = mainHeader.numParts; numParts = mainHeader.numParts;
secondTable = secondHeader.partitionEntriesLBA; secondTable = secondHeader.partitionEntriesLBA;
if (IsLittleEndian() == 0) { /* if (IsLittleEndian() == 0) {
// Reverse partition bytes first, since that function requires non-reversed // Reverse partition bytes first, since that function requires non-reversed
// data from the main header.... // data from the main header....
ReversePartitionBytes(); ReversePartitionBytes();
ReverseHeaderBytes(&mainHeader); ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader); ReverseHeaderBytes(&secondHeader);
} // if } // if */
RecomputeCRCs(); RecomputeCRCs();
/* ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader);
ReversePartitionBytes(); */
if ((allOK) && (!quiet)) { if ((allOK) && (!quiet)) {
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n" 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)) { if (allOK && myDisk.OpenForWrite(device)) {
// Now write the main GPT header... // Now write the main GPT header...
if (myDisk.Seek(1) == 1) { if (myDisk.Seek(1) == 1) {
if (!littleEndian)
ReverseHeaderBytes(&mainHeader);
if (myDisk.Write(&mainHeader, 512) != 512) if (myDisk.Write(&mainHeader, 512) != 512)
allOK = 0; allOK = 0;
if (!littleEndian)
ReverseHeaderBytes(&mainHeader);
} else allOK = 0; // if (myDisk.Seek()...) } else allOK = 0; // if (myDisk.Seek()...)
// Now write the main partition tables... // Now write the main partition tables...
if (allOK) { if (allOK) {
offset = mainHeader.partitionEntriesLBA; offset = mainHeader.partitionEntriesLBA;
if (myDisk.Seek(offset)) { if (myDisk.Seek(offset)) {
if (!littleEndian)
ReversePartitionBytes();
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1) if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0; allOK = 0;
if (!littleEndian)
ReversePartitionBytes();
} else allOK = 0; // if (myDisk.Seek()...) } else allOK = 0; // if (myDisk.Seek()...)
} // if (allOK) } // if (allOK)
@@ -947,17 +972,25 @@ int GPTData::SaveGPTData(int quiet) {
// Now write the secondary partition tables.... // Now write the secondary partition tables....
if (allOK) { if (allOK) {
if (!littleEndian)
ReversePartitionBytes();
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1) if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0; allOK = 0;
if (!littleEndian)
ReversePartitionBytes();
} // if (allOK) } // if (allOK)
// Now write the secondary GPT header... // Now write the secondary GPT header...
if (allOK) { if (allOK) {
offset = mainHeader.backupLBA; offset = mainHeader.backupLBA;
if (!littleEndian)
ReverseHeaderBytes(&secondHeader);
if (myDisk.Seek(offset)) { if (myDisk.Seek(offset)) {
if (myDisk.Write(&secondHeader, 512) == -1) if (myDisk.Write(&secondHeader, 512) == -1)
allOK = 0; allOK = 0;
} else allOK = 0; // if (myDisk.Seek()...) } else allOK = 0; // if (myDisk.Seek()...)
if (!littleEndian)
ReverseHeaderBytes(&secondHeader);
} // if (allOK) } // if (allOK)
// re-read the partition table // re-read the partition table
@@ -982,13 +1015,13 @@ int GPTData::SaveGPTData(int quiet) {
cout << "Aborting write of new partition table.\n"; cout << "Aborting write of new partition table.\n";
} // if } // if
if (IsLittleEndian() == 0) { /* if (IsLittleEndian() == 0) {
// Reverse (normalize) header bytes first, since ReversePartitionBytes() // Reverse (normalize) header bytes first, since ReversePartitionBytes()
// requires non-reversed data in mainHeader... // requires non-reversed data in mainHeader...
ReverseHeaderBytes(&mainHeader); ReverseHeaderBytes(&mainHeader);
ReverseHeaderBytes(&secondHeader); ReverseHeaderBytes(&secondHeader);
ReversePartitionBytes(); ReversePartitionBytes();
} // if } // if */
return (allOK); return (allOK);
} // GPTData::SaveGPTData() } // GPTData::SaveGPTData()
@@ -1005,6 +1038,12 @@ int GPTData::SaveGPTBackup(const string & filename) {
DiskIO backupFile; DiskIO backupFile;
if (backupFile.OpenForWrite(filename)) { 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.... // Reverse the byte order, if necessary....
numParts = mainHeader.numParts; numParts = mainHeader.numParts;
if (IsLittleEndian() == 0) { if (IsLittleEndian() == 0) {
@@ -1013,12 +1052,6 @@ int GPTData::SaveGPTBackup(const string & filename) {
ReverseHeaderBytes(&secondHeader); ReverseHeaderBytes(&secondHeader);
} // if } // 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... // Now write the protective MBR...
protectiveMBR.WriteMBRData(&backupFile); protectiveMBR.WriteMBRData(&backupFile);
@@ -1191,7 +1224,7 @@ void GPTData::DisplayGPTData(void) {
cout << "Disk " << device << ": " << diskSize << " sectors, " cout << "Disk " << device << ": " << diskSize << " sectors, "
<< BytesToSI(diskSize * blockSize) << "\n"; << BytesToSI(diskSize * blockSize) << "\n";
cout << "Logical sector size: " << blockSize << " bytes\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 << "Partition table holds up to " << mainHeader.numParts << " entries\n";
cout << "First usable sector is " << mainHeader.firstUsableLBA cout << "First usable sector is " << mainHeader.firstUsableLBA
<< ", last usable sector is " << mainHeader.lastUsableLBA << "\n"; << ", last usable sector is " << mainHeader.lastUsableLBA << "\n";
@@ -1320,7 +1353,7 @@ void GPTData::CreatePartition(void) {
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock); firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
partitions[partNum].ChangeType(); partitions[partNum].ChangeType();
partitions[partNum].SetName(partitions[partNum].GetNameType()); partitions[partNum].SetDefaultDescription();
} else { } else {
cout << "No free sectors available\n"; cout << "No free sectors available\n";
} // if/else } // if/else
@@ -1551,7 +1584,6 @@ WhichToUse GPTData::UseWhichPartitions(void) {
int GPTData::XFormPartitions(void) { int GPTData::XFormPartitions(void) {
int i, numToConvert; int i, numToConvert;
uint8_t origType; uint8_t origType;
struct newGUID;
// Clear out old data & prepare basics.... // Clear out old data & prepare basics....
ClearGPTData(); ClearGPTData();
@@ -1583,6 +1615,7 @@ int GPTData::XFormPartitions(void) {
// Transforms BSD disklabel on the specified partition (numbered from 0). // Transforms BSD disklabel on the specified partition (numbered from 0).
// If an invalid partition number is given, the program prompts for one. // 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. // Returns the number of new partitions created.
int GPTData::XFormDisklabel(int i) { int GPTData::XFormDisklabel(int i) {
uint32_t low, high, partNum, startPart; uint32_t low, high, partNum, startPart;
@@ -1682,7 +1715,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
do { do {
cout << "Enter an MBR hex code (default " << hex; cout << "Enter an MBR hex code (default " << hex;
cout.width(2); cout.width(2);
cout << typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256 << "): "; cout << partitions[gptPart].GetHexType() / 0x0100 << "): ";
junk = fgets(line, 255, stdin); junk = fgets(line, 255, stdin);
if (line[0] == '\n') if (line[0] == '\n')
typeCode = partitions[gptPart].GetHexType() / 256; 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].SetFirstLBA(startSector);
partitions[partNum].SetLastLBA(endSector); partitions[partNum].SetLastLBA(endSector);
partitions[partNum].SetType(0x0700); partitions[partNum].SetType(0x0700);
partitions[partNum].SetUniqueGUID(1); partitions[partNum].RandomizeUniqueGUID();
} else retval = 0; // if free space until endSector } else retval = 0; // if free space until endSector
} else retval = 0; // if startSector is free } else retval = 0; // if startSector is free
} else retval = 0; // if legal partition number } else retval = 0; // if legal partition number
@@ -2021,9 +2054,7 @@ int GPTData::ClearGPTData(void) {
mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA;
// Set a unique GUID for the disk, based on random numbers // 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.Randomize();
mainHeader.diskGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
mainHeader.diskGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
// Copy main header to backup header // Copy main header to backup header
RebuildSecondHeader(); RebuildSecondHeader();
@@ -2392,8 +2423,7 @@ void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
ReverseBytes(&header->sizeOfPartitionEntries, 4); ReverseBytes(&header->sizeOfPartitionEntries, 4);
ReverseBytes(&header->partitionEntriesCRC, 4); ReverseBytes(&header->partitionEntriesCRC, 4);
ReverseBytes(&header->reserved2, GPT_RESERVED); ReverseBytes(&header->reserved2, GPT_RESERVED);
ReverseBytes(&header->diskGUID.data1, 8); // header->diskGUID.ReverseGUIDBytes();
ReverseBytes(&header->diskGUID.data2, 8);
} // GPTData::ReverseHeaderBytes() } // GPTData::ReverseHeaderBytes()
// IMPORTANT NOTE: This function requires non-reversed mainHeader // 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"; cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n";
allOK = 0; allOK = 0;
} // if } // 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 // Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware
if (IsLittleEndian() == 0) { if (IsLittleEndian() == 0) {
cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly" cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"

5
gpt.h
View File

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

View File

@@ -23,8 +23,6 @@
using namespace std; using namespace std;
PartTypes GPTPart::typeHelper;
GPTPart::GPTPart(void) { GPTPart::GPTPart(void) {
int i; int i;
@@ -37,13 +35,13 @@ GPTPart::~GPTPart(void) {
// Return the gdisk-specific two-byte hex code for the partition // Return the gdisk-specific two-byte hex code for the partition
uint16_t GPTPart::GetHexType(void) { uint16_t GPTPart::GetHexType(void) {
return typeHelper.GUIDToID(partitionType); return partitionType.GetHexType();
} // GPTPart::GetHexType() } // GPTPart::GetHexType()
// Return a plain-text description of the partition type (e.g., "Linux/Windows // Return a plain-text description of the partition type (e.g., "Linux/Windows
// data" or "Linux swap"). // data" or "Linux swap").
string GPTPart::GetNameType(void) { string GPTPart::GetTypeName(void) {
return typeHelper.GUIDToName(partitionType); return partitionType.TypeName();
} // GPTPart::GetNameType() } // GPTPart::GetNameType()
// Compute and return the partition's length (or 0 if the end is incorrectly // 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() } // GPTPart::GetLengthLBA()
// Return partition's name field, converted to a C++ ASCII string // Return partition's name field, converted to a C++ ASCII string
string GPTPart::GetName(void) { string GPTPart::GetDescription(void) {
string theName; string theName;
int i; int i;
@@ -66,32 +64,18 @@ string GPTPart::GetName(void) {
theName += name[i]; theName += name[i];
} // for } // for
return theName; return theName;
} // GPTPart::GetName() } // GPTPart::GetDescription()
// Set the type code to the specified one. Also changes the partition // 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 // name *IF* the current name is the generic one for the current partition
// type. // type.
void GPTPart::SetType(struct GUIDData t) { void GPTPart::SetType(PartType t) {
if (GetName() == typeHelper.GUIDToName(partitionType)) { if (GetDescription() == partitionType.TypeName()) {
SetName(typeHelper.GUIDToName(t)); SetName(t.TypeName());
} // if } // if
partitionType = t; partitionType = t;
} // GPTPart::SetType() } // 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 // 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 // theName is empty. Note that theName is a standard C++-style ASCII
// string, although the GUID partition definition requires a UTF-16LE // string, although the GUID partition definition requires a UTF-16LE
@@ -111,6 +95,7 @@ void GPTPart::SetName(const string & theName) {
// Input is likely to include a newline, so remove it.... // Input is likely to include a newline, so remove it....
i = strlen(newName); i = strlen(newName);
if ((i > 0) && (i <= NAME_SIZE))
if (newName[i - 1] == '\n') if (newName[i - 1] == '\n')
newName[i - 1] = '\0'; newName[i - 1] = '\0';
} else { } else {
@@ -128,6 +113,12 @@ void GPTPart::SetName(const string & theName) {
} // for } // for
} // GPTPart::SetName() } // 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) { GPTPart & GPTPart::operator=(const GPTPart & orig) {
int i; int i;
@@ -159,10 +150,9 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
cout.fill('0'); cout.fill('0');
cout.width(4); cout.width(4);
cout.setf(ios::uppercase); cout.setf(ios::uppercase);
cout << hex << typeHelper.GUIDToID(partitionType) << " " << dec; cout << hex << partitionType.GetHexType() << " " << dec;
cout.fill(' '); cout.fill(' ');
// cout.setf(ios::right); cout << GetDescription().substr(0, 23) << "\n";
cout << GetName().substr(0, 23) << "\n";
cout.fill(' '); cout.fill(' ');
} // if } // if
} // GPTPart::ShowSummary() } // GPTPart::ShowSummary()
@@ -173,9 +163,9 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
uint64_t size; uint64_t size;
if (firstLBA != 0) { if (firstLBA != 0) {
cout << "Partition GUID code: " << GUIDToStr(partitionType); cout << "Partition GUID code: " << partitionType.AsString();
cout << " (" << typeHelper.GUIDToName(partitionType) << ")\n"; cout << " (" << partitionType.TypeName() << ")\n";
cout << "Partition unique GUID: " << GUIDToStr(uniqueGUID) << "\n"; cout << "Partition unique GUID: " << uniqueGUID.AsString() << "\n";
cout << "First sector: " << firstLBA << " (at " cout << "First sector: " << firstLBA << " (at "
<< BytesToSI(firstLBA * blockSize) << ")\n"; << BytesToSI(firstLBA * blockSize) << ")\n";
@@ -190,7 +180,7 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
cout << hex; cout << hex;
cout << attributes << "\n"; cout << attributes << "\n";
cout << dec; cout << dec;
cout << "Partition name: " << GetName() << "\n"; cout << "Partition name: " << GetDescription() << "\n";
cout.fill(' '); cout.fill(' ');
} // if } // if
} // GPTPart::ShowDetails() } // GPTPart::ShowDetails()
@@ -198,12 +188,9 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
// Blank (delete) a single partition // Blank (delete) a single partition
void GPTPart::BlankPartition(void) { void GPTPart::BlankPartition(void) {
int j; int j;
GUIDData zeroGUID;
zeroGUID.data1 = 0; uniqueGUID.Zero();
zeroGUID.data2 = 0; partitionType.Zero();
uniqueGUID = zeroGUID;
partitionType = zeroGUID;
firstLBA = 0; firstLBA = 0;
lastLBA = 0; lastLBA = 0;
attributes = 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. // Reverse the bytes of integral data types; used on big-endian systems.
void GPTPart::ReversePartBytes(void) { void GPTPart::ReversePartBytes(void) {
ReverseBytes(&partitionType.data1, 8); // partitionType.ReverseGUIDBytes();
ReverseBytes(&partitionType.data2, 8); // uniqueGUID.ReverseGUIDBytes();
ReverseBytes(&uniqueGUID.data1, 8);
ReverseBytes(&uniqueGUID.data2, 8);
ReverseBytes(&firstLBA, 8); ReverseBytes(&firstLBA, 8);
ReverseBytes(&lastLBA, 8); ReverseBytes(&lastLBA, 8);
ReverseBytes(&attributes, 8); ReverseBytes(&attributes, 8);
@@ -241,30 +226,34 @@ void GPTPart::ReversePartBytes(void) {
* Functions requiring user interaction * * 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) { void GPTPart::ChangeType(void) {
char line[255]; char line[255];
char* junk; char* junk;
int typeNum = 0xFFFF; unsigned int typeNum = 0xFFFF, changeName = 0;
GUIDData newType;
cout << "Current type is '" << GetNameType() << "'\n"; if (GetDescription() == GetTypeName())
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) { 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): "; cout << "Hex code (L to show codes, 0 to enter raw code, Enter = 0700): ";
junk = fgets(line, 255, stdin); junk = fgets(line, 255, stdin);
sscanf(line, "%X", &typeNum); sscanf(line, "%X", &typeNum);
if ((line[0] == 'L') || (line[0] == 'l')) if ((line[0] == 'L') || (line[0] == 'l'))
typeHelper.ShowTypes(); partitionType.ShowAllTypes();
if (line[0] == '\n') { if (line[0] == '\n') {
typeNum = 0x0700; typeNum = 0x0700;
} // if } // if
} // while } // while
if (typeNum != 0) // user entered a code, so convert it 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 else // user wants to enter the GUID directly, so do that
newType = GetGUID(); partitionType.GetGUIDFromUser();
SetType(newType); cout << "Changed type of partition to '" << partitionType.TypeName() << "'\n";
cout << "Changed type of partition to '" << typeHelper.GUIDToName(partitionType) << "'\n"; if (changeName) {
SetDefaultDescription();
} // if
} // GPTPart::ChangeType() } // GPTPart::ChangeType()
/*********************************** /***********************************

View File

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

20
mbr.cc
View File

@@ -39,6 +39,7 @@ MBRData::MBRData(void) {
numHeads = MAX_HEADS; numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK; numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL; myDisk = NULL;
canDeleteMyDisk = 0;
EmptyMBR(); EmptyMBR();
} // MBRData default constructor } // MBRData default constructor
@@ -50,6 +51,7 @@ MBRData::MBRData(string filename) {
numHeads = MAX_HEADS; numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK; numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL; myDisk = NULL;
canDeleteMyDisk = 0;
srand((unsigned int) time(NULL)); srand((unsigned int) time(NULL));
// Try to read the specified partition table, but if it fails.... // Try to read the specified partition table, but if it fails....
@@ -59,8 +61,12 @@ MBRData::MBRData(string filename) {
} // if } // if
} // MBRData(string filename) constructor } // 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) { MBRData::~MBRData(void) {
// delete myDisk; if (canDeleteMyDisk)
delete myDisk;
} // MBRData destructor } // MBRData destructor
/********************** /**********************
@@ -74,8 +80,10 @@ MBRData::~MBRData(void) {
int MBRData::ReadMBRData(const string & deviceFilename) { int MBRData::ReadMBRData(const string & deviceFilename) {
int allOK = 1; int allOK = 1;
if (myDisk == NULL) if (myDisk == NULL) {
myDisk = new DiskIO; myDisk = new DiskIO;
canDeleteMyDisk = 1;
} // if
if (myDisk->OpenForRead(deviceFilename)) { if (myDisk->OpenForRead(deviceFilename)) {
ReadMBRData(myDisk); ReadMBRData(myDisk);
} else { } else {
@@ -98,8 +106,10 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
int err = 1; int err = 1;
TempMBR tempMBR; TempMBR tempMBR;
if (myDisk != NULL) if ((myDisk != NULL) && (canDeleteMyDisk)) {
delete myDisk; delete myDisk;
canDeleteMyDisk = 0;
} // if
myDisk = theDisk; myDisk = theDisk;
@@ -831,9 +841,9 @@ GPTPart MBRData::AsGPT(int i) {
if (lastSector > 0) lastSector--; if (lastSector > 0) lastSector--;
newPart.SetLastLBA(lastSector); newPart.SetLastLBA(lastSector);
newPart.SetType(((uint16_t) origType) * 0x0100); newPart.SetType(((uint16_t) origType) * 0x0100);
newPart.SetUniqueGUID(1); newPart.RandomizeUniqueGUID();
newPart.SetAttributes(0); newPart.SetAttributes(0);
newPart.SetName(newPart.GetNameType()); newPart.SetName(newPart.GetTypeName());
} // if not extended, protective, or non-existent } // if not extended, protective, or non-existent
} // if (origPart != NULL) } // if (origPart != NULL)
return newPart; return newPart;

1
mbr.h
View File

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

View File

@@ -16,9 +16,9 @@
using namespace std; using namespace std;
int PartTypes::numInstances = 0; int PartType::numInstances = 0;
AType* PartTypes::allTypes = NULL; AType* PartType::allTypes = NULL;
AType* PartTypes::lastType = NULL; AType* PartType::lastType = NULL;
// Constructor. Its main task is to initialize the data list, but only // 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. // 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. // by typing "L" at the main gdisk menu.
// See http://www.win.tue.nl/~aeb/partitions/partition_types-1.html // See http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
// for a list of MBR partition type codes. // for a list of MBR partition type codes.
PartTypes::PartTypes(void) { PartType::PartType(void) : GUIDData() {
numInstances++; numInstances++;
if (numInstances == 1) { if (numInstances == 1) {
AddAllTypes();
// 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
} // if } // if
} // default constructor } // 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; AType* tempType;
numInstances--; numInstances--;
@@ -203,19 +65,117 @@ PartTypes::~PartTypes(void) {
} // if } // if
} // destructor } // 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 // Add a single type to the linked list of types. Returns 1 if operation
// succeeds, 0 otherwise. // succeeds, 0 otherwise.
int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2, int PartType::AddType(uint16_t mbrType, const char * guidData, const char * name,
const char * n, int toDisplay) { int toDisplay) {
AType* tempType; AType* tempType;
int allOK = 1; int allOK = 1;
tempType = new AType; tempType = new AType;
if (tempType != NULL) { if (tempType != NULL) {
tempType->MBRType = mbrType; tempType->MBRType = mbrType;
tempType->GUIDType.data1 = guidData1; tempType->GUIDType = guidData;
tempType->GUIDType.data2 = guidData2; tempType->name = name;
tempType->name = n;
tempType->display = toDisplay; tempType->display = toDisplay;
tempType->next = NULL; tempType->next = NULL;
if (allTypes == NULL) { // first entry if (allTypes == NULL) { // first entry
@@ -228,13 +188,85 @@ int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
allOK = 0; allOK = 0;
} // if/else } // if/else
return allOK; 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.... // Displays the available types and my extended MBR codes for same....
// Note: This function assumes an 80-column display. On wider displays, // Note: This function assumes an 80-column display. On wider displays,
// it stops at under 80 columns; on narrower displays, lines will wrap // it stops at under 80 columns; on narrower displays, lines will wrap
// in an ugly way. // in an ugly way.
void PartTypes::ShowTypes(void) { void PartType::ShowAllTypes(void) {
int colCount = 1; // column count int colCount = 1; // column count
size_t i; size_t i;
AType* thisType = allTypes; AType* thisType = allTypes;
@@ -257,10 +289,10 @@ void PartTypes::ShowTypes(void) {
} // while } // while
cout.fill(' '); cout.fill(' ');
cout << "\n" << dec; cout << "\n" << dec;
} // PartTypes::ShowTypes() } // PartType::ShowTypes()
// Returns 1 if code is a valid extended MBR code, 0 if it's not // 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; AType* thisType = allTypes;
int found = 0; int found = 0;
@@ -271,85 +303,4 @@ int PartTypes::Valid(uint16_t code) {
thisType = thisType->next; thisType = thisType->next;
} // while } // while
return found; return found;
} // PartTypes::Valid() } // PartType::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()

View File

@@ -6,6 +6,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include "support.h" #include "support.h"
#include "guid.h"
#ifndef __PARTITION_TYPES #ifndef __PARTITION_TYPES
#define __PARTITION_TYPES #define __PARTITION_TYPES
@@ -18,27 +19,42 @@ struct AType {
// type codes, so as to permit disambiguation and use of new // type codes, so as to permit disambiguation and use of new
// codes required by GPT // codes required by GPT
uint16_t MBRType; uint16_t MBRType;
struct GUIDData GUIDType; GUIDData GUIDType;
string name; string name;
int display; // 1 to show to users as available type, 0 not to int display; // 1 to show to users as available type, 0 not to
AType* next; AType* next;
}; // struct AType }; // struct AType
class PartTypes { class PartType : public GUIDData {
protected: protected:
static int numInstances; static int numInstances;
static AType* allTypes; // Linked list holding all the data static AType* allTypes; // Linked list holding all the data
static AType* lastType; // Pointer to last entry in the list static AType* lastType; // Pointer to last entry in the list
void AddAllTypes(void);
public: public:
PartTypes(void); PartType(void);
~PartTypes(void); PartType(const PartType & orig);
int AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2, PartType(const GUIDData & orig);
const char * name, int toDisplay = 1); ~PartType(void);
void ShowTypes(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); int Valid(uint16_t);
string GUIDToName(struct GUIDData typeCode);
struct GUIDData IDToGUID(uint16_t ID);
uint16_t GUIDToID(struct GUIDData);
}; };
#endif #endif

View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com) .\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License .\" 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" .SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS" .SH "SYNOPSIS"

View File

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

View File

@@ -200,112 +200,19 @@ string BytesToSI(uint64_t size) {
return theValue; return theValue;
} // BlocksToSI() } // BlocksToSI()
// Return a plain-text name for a partition type. // Converts two consecutive characters in the input string into a
// Convert a GUID to a string representation, suitable for display // number, interpreting the string as a hexadecimal number, starting
// to humans.... // at the specified position.
string GUIDToStr(struct GUIDData theGUID) { unsigned char StrToHex(const string & input, unsigned int position) {
unsigned long long blocks[11]; unsigned char retval = 0x00;
char theString[40]; unsigned int temp;
theString[0] = '\0';; if (input.length() >= (position + 2)) {
blocks[0] = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF)); sscanf(input.substr(position, 2).c_str(), "%x", &temp);
blocks[1] = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32; retval = (unsigned char) temp;
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 } // if
return retval;
// If neither of the above methods of entry was used, use prompted } // StrToHex()
// 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 1 if the CPU architecture is little endian, 0 if it's big endian.... // Return 1 if the CPU architecture is little endian, 0 if it's big endian....
int IsLittleEndian(void) { int IsLittleEndian(void) {

View File

@@ -23,11 +23,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#endif #endif
/* #ifdef __FreeBSD__
#define fstat64 fstat
#define stat64 stat
#endif */
// Set this as a default // Set this as a default
#define SECTOR_SIZE UINT32_C(512) #define SECTOR_SIZE UINT32_C(512)
@@ -53,20 +48,11 @@
using namespace std; 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); int GetNumber(int low, int high, int def, const string & prompt);
char GetYN(void); char GetYN(void);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt); uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt);
string BytesToSI(uint64_t size); string BytesToSI(uint64_t size);
string GUIDToStr(struct GUIDData theGUID); unsigned char StrToHex(const string & input, unsigned int position);
GUIDData GetGUID(void);
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian 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 void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
uint64_t PowerOf2(int value); uint64_t PowerOf2(int value);