diff options
-rw-r--r-- | CHANGELOG | 27 | ||||
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | Makefile.mingw | 9 | ||||
-rw-r--r-- | README | 35 | ||||
-rw-r--r-- | README.Windows | 9 | ||||
-rw-r--r-- | attributes.cc | 2 | ||||
-rw-r--r-- | bsd.cc | 4 | ||||
-rw-r--r-- | gdisk.8 | 2 | ||||
-rw-r--r-- | gdisk.cc | 12 | ||||
-rw-r--r-- | gpt.cc | 118 | ||||
-rw-r--r-- | gpt.h | 5 | ||||
-rw-r--r-- | gptpart.cc | 93 | ||||
-rw-r--r-- | gptpart.h | 24 | ||||
-rw-r--r-- | mbr.cc | 20 | ||||
-rw-r--r-- | mbr.h | 1 | ||||
-rw-r--r-- | parttypes.cc | 445 | ||||
-rw-r--r-- | parttypes.h | 36 | ||||
-rw-r--r-- | sgdisk.8 | 2 | ||||
-rw-r--r-- | sgdisk.cc | 4 | ||||
-rw-r--r-- | support.cc | 117 | ||||
-rw-r--r-- | support.h | 16 |
21 files changed, 468 insertions, 522 deletions
@@ -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): ------------------ @@ -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) diff --git a/Makefile.mingw b/Makefile.mingw index 1a59f2d..96ef8a0 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -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) @@ -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 ------- diff --git a/README.Windows b/README.Windows index a88d29d..91074c4 100644 --- a/README.Windows +++ b/README.Windows @@ -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
----------------------------------
diff --git a/attributes.cc b/attributes.cc index 9bdd428..b0800fa 100644 --- a/attributes.cc +++ b/attributes.cc @@ -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"; @@ -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() @@ -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" @@ -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(); @@ -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" @@ -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: @@ -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() /*********************************** @@ -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); @@ -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; @@ -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 diff --git a/parttypes.cc b/parttypes.cc index 85ce6b0..850b1e3 100644 --- a/parttypes.cc +++ b/parttypes.cc @@ -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,122 +188,70 @@ int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2, allOK = 0; } // if/else return allOK; -} // PartTypes::AddType() - -// 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) { - int colCount = 1; // column count - size_t i; - AType* thisType = allTypes; +} // GUID::AddType(const char* variant) - cout.unsetf(ios::uppercase); - while (thisType != NULL) { - if (thisType->display == 1) { // show it - cout.fill('0'); - cout.width(4); - cout << hex << thisType->MBRType << " "; - cout << thisType->name.substr(0, 20); - for (i = 0; i < (20 - (thisType->name.substr(0, 20).length())); i++) cout << " "; - if ((colCount % 3) == 0) - cout << "\n"; - else - cout << " "; - colCount++; - } // if - thisType = thisType->next; - } // while - cout.fill(' '); - cout << "\n" << dec; -} // PartTypes::ShowTypes() - -// Returns 1 if code is a valid extended MBR code, 0 if it's not -int PartTypes::Valid(uint16_t code) { - AType* thisType = allTypes; - int found = 0; - - while ((thisType != NULL) && (!found)) { - if (thisType->MBRType == code) { - found = 1; - } // if - thisType = thisType->next; - } // while - return found; -} // PartTypes::Valid() - -// Convert a GUID code to a name. -string PartTypes::GUIDToName(struct GUIDData typeCode) { +// 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; - string typeName; + // 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->GUIDType.data1 == typeCode.data1) && - (theItem->GUIDType.data2 == typeCode.data2)) { // found it! - typeName = theItem->name; - found = 1; + if (theItem->MBRType == ID) { // found it! + GUIDData::operator=(theItem->GUIDType); + found = 1; } else { theItem = theItem->next; } // if/else } // while if (!found) { - typeName = "Unknown"; + 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 typeName; -} // PartTypes::GUIDToName() + return *this; +} // PartType::operator=(uint16_t ID) -// 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) { +// Return the English description of the partition type (e.g., "Linux/Windows data") +string PartType::TypeName(void) { 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); + string typeName; - // 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; + if (theItem->GUIDType == *this) { // found it! + typeName = theItem->name; + 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(' '); + typeName = "Unknown"; } // if (!found) - return theGUID; -} // PartTypes::IDToGUID() + return typeName; +} // PartType::TypeName() -// Convert a GUID to a 16-bit variant of the MBR ID number. +// 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 PartTypes::GUIDToID(struct GUIDData typeCode) { +uint16_t PartType::GetHexType() { 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! + if ((theItem->GUIDType == *this) && (theItem->display == 1)) { // found it! theID = theItem->MBRType; - found = 1; + found = 1; } else { theItem = theItem->next; } // if/else @@ -352,4 +260,47 @@ uint16_t PartTypes::GUIDToID(struct GUIDData typeCode) { theID = 0xFFFF; } // if (!found) return theID; -} // PartTypes::GUIDToID() +} // 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 PartType::ShowAllTypes(void) { + int colCount = 1; // column count + size_t i; + AType* thisType = allTypes; + + cout.unsetf(ios::uppercase); + while (thisType != NULL) { + if (thisType->display == 1) { // show it + cout.fill('0'); + cout.width(4); + cout << hex << thisType->MBRType << " "; + cout << thisType->name.substr(0, 20); + for (i = 0; i < (20 - (thisType->name.substr(0, 20).length())); i++) cout << " "; + if ((colCount % 3) == 0) + cout << "\n"; + else + cout << " "; + colCount++; + } // if + thisType = thisType->next; + } // while + cout.fill(' '); + cout << "\n" << dec; +} // PartType::ShowTypes() + +// Returns 1 if code is a valid extended MBR code, 0 if it's not +int PartType::Valid(uint16_t code) { + AType* thisType = allTypes; + int found = 0; + + while ((thisType != NULL) && (!found)) { + if (thisType->MBRType == code) { + found = 1; + } // if + thisType = thisType->next; + } // while + return found; +} // PartType::Valid() diff --git a/parttypes.h b/parttypes.h index 1534a52..1f82d1d 100644 --- a/parttypes.h +++ b/parttypes.h @@ -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 @@ -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" @@ -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; @@ -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]; - - 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; +// 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; + + 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) { @@ -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); |