Version 0.6.3 release. Big-endian bug fix, new GUID generation method,
architectural changes.
This commit is contained in:
27
CHANGELOG
27
CHANGELOG
@@ -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):
|
||||
------------------
|
||||
|
||||
|
||||
9
Makefile
9
Makefile
@@ -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)
|
||||
|
||||
@@ -2,8 +2,9 @@ CC=/usr/bin/i586-mingw32msvc-gcc
|
||||
CXX=/usr/bin/i586-mingw32msvc-g++
|
||||
STRIP=/usr/bin/i586-mingw32msvc-strip
|
||||
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
|
||||
CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
|
||||
LIB_NAMES=gptpart bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows
|
||||
CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -g
|
||||
#CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
|
||||
LIB_NAMES=guid gptpart bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows
|
||||
LIB_SRCS=$(NAMES:=.cc)
|
||||
LIB_OBJS=$(LIB_NAMES:=.o)
|
||||
LIB_HEADERS=$(LIB_NAMES:=.h)
|
||||
@@ -12,10 +13,10 @@ DEPEND= makedepend $(CFLAGS)
|
||||
all: gdisk
|
||||
|
||||
gdisk: $(LIB_OBJS) gdisk.o
|
||||
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk.exe
|
||||
$(CXX) $(LIB_OBJS) gdisk.o -luuid -o gdisk.exe
|
||||
|
||||
sgdisk: $(LIB_OBJS) sgdisk.o
|
||||
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk.exe
|
||||
$(CXX) $(LIB_OBJS) sgdisk.o -lpopt -o sgdisk.exe
|
||||
|
||||
lint: #no pre-reqs
|
||||
lint $(SRCS)
|
||||
|
||||
35
README
35
README
@@ -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
|
||||
-------
|
||||
|
||||
@@ -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
|
||||
----------------------------------
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Attributes::Attributes(void) {
|
||||
} // for
|
||||
|
||||
// Now reset those names that are defined....
|
||||
atNames[0] = "system partition";
|
||||
atNames[0] = "system partition"; // required for computer to operate
|
||||
atNames[60] = "read-only";
|
||||
atNames[62] = "hidden";
|
||||
atNames[63] = "do not automount";
|
||||
|
||||
4
bsd.cc
4
bsd.cc
@@ -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()
|
||||
|
||||
2
gdisk.8
2
gdisk.8
@@ -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"
|
||||
|
||||
12
gdisk.cc
12
gdisk.cc
@@ -29,6 +29,7 @@ int main(int argc, char* argv[]) {
|
||||
GPTData theGPT;
|
||||
int doMore = 1;
|
||||
char* device = NULL;
|
||||
PartType typeHelper; // unused, but necessary to initialize partition type linked list
|
||||
|
||||
cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n";
|
||||
|
||||
@@ -76,7 +77,7 @@ void MainMenu(string filename, struct GPTData* theGPT) {
|
||||
char command, line[255], buFile[255];
|
||||
char* junk;
|
||||
int goOn = 1;
|
||||
PartTypes typeHelper;
|
||||
PartType typeHelper;
|
||||
uint32_t temp1, temp2;
|
||||
|
||||
do {
|
||||
@@ -105,7 +106,7 @@ void MainMenu(string filename, struct GPTData* theGPT) {
|
||||
theGPT->ShowDetails();
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
typeHelper.ShowTypes();
|
||||
typeHelper.ShowAllTypes();
|
||||
break;
|
||||
case 'n': case 'N':
|
||||
theGPT->CreatePartition();
|
||||
@@ -177,7 +178,6 @@ void ShowCommands(void) {
|
||||
void RecoveryMenu(string filename, struct GPTData* theGPT) {
|
||||
char command, line[255], buFile[255];
|
||||
char* junk;
|
||||
PartTypes typeHelper;
|
||||
uint32_t temp1;
|
||||
int goOn = 1;
|
||||
|
||||
@@ -303,10 +303,10 @@ void ShowRecoveryCommands(void) {
|
||||
void ExpertsMenu(string filename, struct GPTData* theGPT) {
|
||||
char command, line[255];
|
||||
char* junk;
|
||||
PartTypes typeHelper;
|
||||
uint32_t pn;
|
||||
uint32_t temp1, temp2;
|
||||
int goOn = 1;
|
||||
GUIDData aGUID;
|
||||
|
||||
do {
|
||||
cout << "\nExpert command (? for help): ";
|
||||
@@ -325,7 +325,7 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
|
||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
|
||||
pn = theGPT->GetPartNum();
|
||||
cout << "Enter the partition's new unique GUID:\n";
|
||||
theGPT->SetPartitionGUID(pn, GetGUID());
|
||||
theGPT->SetPartitionGUID(pn, aGUID.GetGUIDFromUser());
|
||||
} else cout << "No partitions\n";
|
||||
break;
|
||||
case 'd': case 'D':
|
||||
@@ -338,7 +338,7 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
|
||||
break;
|
||||
case 'g': case 'G':
|
||||
cout << "Enter the disk's unique GUID:\n";
|
||||
theGPT->SetDiskGUID(GetGUID());
|
||||
theGPT->SetDiskGUID(aGUID.GetGUIDFromUser());
|
||||
break;
|
||||
case 'i': case 'I':
|
||||
theGPT->ShowDetails();
|
||||
|
||||
118
gpt.cc
118
gpt.cc
@@ -173,12 +173,11 @@ int GPTData::Verify(void) {
|
||||
<< secondHeader.lastUsableLBA << ")\n"
|
||||
<< "The 'e' option on the experts' menu can probably fix this problem.\n";
|
||||
} // if
|
||||
if ((mainHeader.diskGUID.data1 != secondHeader.diskGUID.data1) ||
|
||||
(mainHeader.diskGUID.data2 != secondHeader.diskGUID.data2)) {
|
||||
if ((mainHeader.diskGUID != secondHeader.diskGUID)) {
|
||||
problems++;
|
||||
cout << "\nProblem: main header's disk GUID (" << GUIDToStr(mainHeader.diskGUID)
|
||||
cout << "\nProblem: main header's disk GUID (" << mainHeader.diskGUID.AsString()
|
||||
<< ") doesn't\nmatch the backup GPT header's disk GUID ("
|
||||
<< GUIDToStr(secondHeader.diskGUID) << ")\n"
|
||||
<< secondHeader.diskGUID.AsString() << ")\n"
|
||||
<< "You should use the 'b' or 'd' option on the recovery & transformation menu to\n"
|
||||
<< "select one or the other header.\n";
|
||||
} // if
|
||||
@@ -368,8 +367,9 @@ int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
||||
return (oldCRC == newCRC);
|
||||
} // GPTData::CheckHeaderCRC()
|
||||
|
||||
// Recompute all the CRCs. Must be called before saving (but after reversing
|
||||
// byte order on big-endian systems) if any changes have been made.
|
||||
// Recompute all the CRCs. Must be called before saving if any changes have
|
||||
// been made. Must be called on platform-ordered data (this function reverses
|
||||
// byte order and then undoes that reversal.)
|
||||
void GPTData::RecomputeCRCs(void) {
|
||||
uint32_t crc, hSize, trueNumParts;
|
||||
int littleEndian = 1;
|
||||
@@ -377,13 +377,21 @@ void GPTData::RecomputeCRCs(void) {
|
||||
// Initialize CRC functions...
|
||||
chksum_crc32gentab();
|
||||
|
||||
// Save some key data from header before reversing byte order....
|
||||
trueNumParts = mainHeader.numParts;
|
||||
hSize = mainHeader.headerSize;
|
||||
littleEndian = IsLittleEndian();
|
||||
|
||||
if ((littleEndian = IsLittleEndian()) == 0) {
|
||||
ReversePartitionBytes();
|
||||
ReverseHeaderBytes(&mainHeader);
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
} // if
|
||||
/* if ((littleEndian = IsLittleEndian()) == 0) {
|
||||
ReverseBytes(&trueNumParts, 4);
|
||||
ReverseBytes(&hSize, 4);
|
||||
} // if */
|
||||
|
||||
// Compute CRC of partition tables & store in main and secondary headers
|
||||
trueNumParts = mainHeader.numParts;
|
||||
if (littleEndian == 0)
|
||||
ReverseBytes(&trueNumParts, 4); // unreverse this key piece of data....
|
||||
crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
|
||||
mainHeader.partitionEntriesCRC = crc;
|
||||
secondHeader.partitionEntriesCRC = crc;
|
||||
@@ -405,6 +413,12 @@ void GPTData::RecomputeCRCs(void) {
|
||||
if (littleEndian == 0)
|
||||
ReverseBytes(&crc, 4);
|
||||
secondHeader.headerCRC = crc;
|
||||
|
||||
if ((littleEndian = IsLittleEndian()) == 0) {
|
||||
ReverseHeaderBytes(&mainHeader);
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
ReversePartitionBytes();
|
||||
} // if
|
||||
} // GPTData::RecomputeCRCs()
|
||||
|
||||
// Rebuild the main GPT header, using the secondary header as a model.
|
||||
@@ -421,8 +435,7 @@ void GPTData::RebuildMainHeader(void) {
|
||||
mainHeader.backupLBA = secondHeader.currentLBA;
|
||||
mainHeader.firstUsableLBA = secondHeader.firstUsableLBA;
|
||||
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA;
|
||||
mainHeader.diskGUID.data1 = secondHeader.diskGUID.data1;
|
||||
mainHeader.diskGUID.data2 = secondHeader.diskGUID.data2;
|
||||
mainHeader.diskGUID = secondHeader.diskGUID;
|
||||
mainHeader.partitionEntriesLBA = UINT64_C(2);
|
||||
mainHeader.numParts = secondHeader.numParts;
|
||||
mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries;
|
||||
@@ -445,8 +458,7 @@ void GPTData::RebuildSecondHeader(void) {
|
||||
secondHeader.backupLBA = mainHeader.currentLBA;
|
||||
secondHeader.firstUsableLBA = mainHeader.firstUsableLBA;
|
||||
secondHeader.lastUsableLBA = mainHeader.lastUsableLBA;
|
||||
secondHeader.diskGUID.data1 = mainHeader.diskGUID.data1;
|
||||
secondHeader.diskGUID.data2 = mainHeader.diskGUID.data2;
|
||||
secondHeader.diskGUID = mainHeader.diskGUID;
|
||||
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
|
||||
secondHeader.numParts = mainHeader.numParts;
|
||||
secondHeader.sizeOfPartitionEntries = mainHeader.sizeOfPartitionEntries;
|
||||
@@ -836,12 +848,14 @@ int GPTData::LoadSecondTableAsMain(void) {
|
||||
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
|
||||
// write, 0 if there was a problem.
|
||||
int GPTData::SaveGPTData(int quiet) {
|
||||
int allOK = 1;
|
||||
int allOK = 1, littleEndian;
|
||||
char answer;
|
||||
uint64_t secondTable;
|
||||
uint32_t numParts;
|
||||
uint64_t offset;
|
||||
|
||||
littleEndian = IsLittleEndian();
|
||||
|
||||
if (device == "") {
|
||||
cerr << "Device not defined.\n";
|
||||
} // if
|
||||
@@ -894,14 +908,17 @@ int GPTData::SaveGPTData(int quiet) {
|
||||
// big-endian systems....
|
||||
numParts = mainHeader.numParts;
|
||||
secondTable = secondHeader.partitionEntriesLBA;
|
||||
if (IsLittleEndian() == 0) {
|
||||
/* if (IsLittleEndian() == 0) {
|
||||
// Reverse partition bytes first, since that function requires non-reversed
|
||||
// data from the main header....
|
||||
ReversePartitionBytes();
|
||||
ReverseHeaderBytes(&mainHeader);
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
} // if
|
||||
} // if */
|
||||
RecomputeCRCs();
|
||||
/* ReverseHeaderBytes(&mainHeader);
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
ReversePartitionBytes(); */
|
||||
|
||||
if ((allOK) && (!quiet)) {
|
||||
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"
|
||||
@@ -922,16 +939,24 @@ int GPTData::SaveGPTData(int quiet) {
|
||||
if (allOK && myDisk.OpenForWrite(device)) {
|
||||
// Now write the main GPT header...
|
||||
if (myDisk.Seek(1) == 1) {
|
||||
if (!littleEndian)
|
||||
ReverseHeaderBytes(&mainHeader);
|
||||
if (myDisk.Write(&mainHeader, 512) != 512)
|
||||
allOK = 0;
|
||||
if (!littleEndian)
|
||||
ReverseHeaderBytes(&mainHeader);
|
||||
} else allOK = 0; // if (myDisk.Seek()...)
|
||||
|
||||
// Now write the main partition tables...
|
||||
if (allOK) {
|
||||
offset = mainHeader.partitionEntriesLBA;
|
||||
if (myDisk.Seek(offset)) {
|
||||
if (!littleEndian)
|
||||
ReversePartitionBytes();
|
||||
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
|
||||
allOK = 0;
|
||||
if (!littleEndian)
|
||||
ReversePartitionBytes();
|
||||
} else allOK = 0; // if (myDisk.Seek()...)
|
||||
} // if (allOK)
|
||||
|
||||
@@ -947,18 +972,26 @@ int GPTData::SaveGPTData(int quiet) {
|
||||
|
||||
// Now write the secondary partition tables....
|
||||
if (allOK) {
|
||||
if (!littleEndian)
|
||||
ReversePartitionBytes();
|
||||
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
|
||||
allOK = 0;
|
||||
} // if (allOK)
|
||||
if (!littleEndian)
|
||||
ReversePartitionBytes();
|
||||
} // if (allOK)
|
||||
|
||||
// Now write the secondary GPT header...
|
||||
if (allOK) {
|
||||
offset = mainHeader.backupLBA;
|
||||
if (myDisk.Seek(offset)) {
|
||||
if (!littleEndian)
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
if (myDisk.Seek(offset)) {
|
||||
if (myDisk.Write(&secondHeader, 512) == -1)
|
||||
allOK = 0;
|
||||
} else allOK = 0; // if (myDisk.Seek()...)
|
||||
} // if (allOK)
|
||||
if (!littleEndian)
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
} // if (allOK)
|
||||
|
||||
// re-read the partition table
|
||||
if (allOK) {
|
||||
@@ -982,13 +1015,13 @@ int GPTData::SaveGPTData(int quiet) {
|
||||
cout << "Aborting write of new partition table.\n";
|
||||
} // if
|
||||
|
||||
if (IsLittleEndian() == 0) {
|
||||
/* if (IsLittleEndian() == 0) {
|
||||
// Reverse (normalize) header bytes first, since ReversePartitionBytes()
|
||||
// requires non-reversed data in mainHeader...
|
||||
ReverseHeaderBytes(&mainHeader);
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
ReversePartitionBytes();
|
||||
} // if
|
||||
} // if */
|
||||
|
||||
return (allOK);
|
||||
} // GPTData::SaveGPTData()
|
||||
@@ -1005,6 +1038,12 @@ int GPTData::SaveGPTBackup(const string & filename) {
|
||||
DiskIO backupFile;
|
||||
|
||||
if (backupFile.OpenForWrite(filename)) {
|
||||
// Recomputing the CRCs is likely to alter them, which could be bad
|
||||
// if the intent is to save a potentially bad GPT for later analysis;
|
||||
// but if we don't do this, we get bogus errors when we load the
|
||||
// backup. I'm favoring misses over false alarms....
|
||||
RecomputeCRCs();
|
||||
|
||||
// Reverse the byte order, if necessary....
|
||||
numParts = mainHeader.numParts;
|
||||
if (IsLittleEndian() == 0) {
|
||||
@@ -1013,12 +1052,6 @@ int GPTData::SaveGPTBackup(const string & filename) {
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
} // if
|
||||
|
||||
// Recomputing the CRCs is likely to alter them, which could be bad
|
||||
// if the intent is to save a potentially bad GPT for later analysis;
|
||||
// but if we don't do this, we get bogus errors when we load the
|
||||
// backup. I'm favoring misses over false alarms....
|
||||
RecomputeCRCs();
|
||||
|
||||
// Now write the protective MBR...
|
||||
protectiveMBR.WriteMBRData(&backupFile);
|
||||
|
||||
@@ -1191,7 +1224,7 @@ void GPTData::DisplayGPTData(void) {
|
||||
cout << "Disk " << device << ": " << diskSize << " sectors, "
|
||||
<< BytesToSI(diskSize * blockSize) << "\n";
|
||||
cout << "Logical sector size: " << blockSize << " bytes\n";
|
||||
cout << "Disk identifier (GUID): " << GUIDToStr(mainHeader.diskGUID) << "\n";
|
||||
cout << "Disk identifier (GUID): " << mainHeader.diskGUID.AsString() << "\n";
|
||||
cout << "Partition table holds up to " << mainHeader.numParts << " entries\n";
|
||||
cout << "First usable sector is " << mainHeader.firstUsableLBA
|
||||
<< ", last usable sector is " << mainHeader.lastUsableLBA << "\n";
|
||||
@@ -1320,7 +1353,7 @@ void GPTData::CreatePartition(void) {
|
||||
|
||||
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
|
||||
partitions[partNum].ChangeType();
|
||||
partitions[partNum].SetName(partitions[partNum].GetNameType());
|
||||
partitions[partNum].SetDefaultDescription();
|
||||
} else {
|
||||
cout << "No free sectors available\n";
|
||||
} // if/else
|
||||
@@ -1551,7 +1584,6 @@ WhichToUse GPTData::UseWhichPartitions(void) {
|
||||
int GPTData::XFormPartitions(void) {
|
||||
int i, numToConvert;
|
||||
uint8_t origType;
|
||||
struct newGUID;
|
||||
|
||||
// Clear out old data & prepare basics....
|
||||
ClearGPTData();
|
||||
@@ -1567,7 +1599,7 @@ int GPTData::XFormPartitions(void) {
|
||||
// don't waste CPU time trying to convert extended, hybrid protective, or
|
||||
// null (non-existent) partitions
|
||||
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
|
||||
(origType != 0x00) && (origType != 0xEE))
|
||||
(origType != 0x00) && (origType != 0xEE))
|
||||
partitions[i] = protectiveMBR.AsGPT(i);
|
||||
} // for
|
||||
|
||||
@@ -1583,6 +1615,7 @@ int GPTData::XFormPartitions(void) {
|
||||
|
||||
// Transforms BSD disklabel on the specified partition (numbered from 0).
|
||||
// If an invalid partition number is given, the program prompts for one.
|
||||
// (Default for i is -1; called without an option, it therefore prompts.)
|
||||
// Returns the number of new partitions created.
|
||||
int GPTData::XFormDisklabel(int i) {
|
||||
uint32_t low, high, partNum, startPart;
|
||||
@@ -1635,7 +1668,7 @@ int GPTData::XFormDisklabel(BSDData* disklabel, uint32_t startPart) {
|
||||
int i, numDone = 0;
|
||||
|
||||
if ((disklabel->IsDisklabel()) && (startPart >= 0) &&
|
||||
(startPart < mainHeader.numParts)) {
|
||||
(startPart < mainHeader.numParts)) {
|
||||
for (i = 0; i < disklabel->GetNumParts(); i++) {
|
||||
partitions[i + startPart] = disklabel->AsGPT(i);
|
||||
if (partitions[i + startPart].GetFirstLBA() != UINT64_C(0))
|
||||
@@ -1682,7 +1715,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
||||
do {
|
||||
cout << "Enter an MBR hex code (default " << hex;
|
||||
cout.width(2);
|
||||
cout << typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256 << "): ";
|
||||
cout << partitions[gptPart].GetHexType() / 0x0100 << "): ";
|
||||
junk = fgets(line, 255, stdin);
|
||||
if (line[0] == '\n')
|
||||
typeCode = partitions[gptPart].GetHexType() / 256;
|
||||
@@ -1948,7 +1981,7 @@ uint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64
|
||||
partitions[partNum].SetFirstLBA(startSector);
|
||||
partitions[partNum].SetLastLBA(endSector);
|
||||
partitions[partNum].SetType(0x0700);
|
||||
partitions[partNum].SetUniqueGUID(1);
|
||||
partitions[partNum].RandomizeUniqueGUID();
|
||||
} else retval = 0; // if free space until endSector
|
||||
} else retval = 0; // if startSector is free
|
||||
} else retval = 0; // if legal partition number
|
||||
@@ -2021,9 +2054,7 @@ int GPTData::ClearGPTData(void) {
|
||||
mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA;
|
||||
|
||||
// Set a unique GUID for the disk, based on random numbers
|
||||
// rand() is only 32 bits, so multiply together to fill a 64-bit value
|
||||
mainHeader.diskGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
|
||||
mainHeader.diskGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
|
||||
mainHeader.diskGUID.Randomize();
|
||||
|
||||
// Copy main header to backup header
|
||||
RebuildSecondHeader();
|
||||
@@ -2392,8 +2423,7 @@ void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
|
||||
ReverseBytes(&header->sizeOfPartitionEntries, 4);
|
||||
ReverseBytes(&header->partitionEntriesCRC, 4);
|
||||
ReverseBytes(&header->reserved2, GPT_RESERVED);
|
||||
ReverseBytes(&header->diskGUID.data1, 8);
|
||||
ReverseBytes(&header->diskGUID.data2, 8);
|
||||
// header->diskGUID.ReverseGUIDBytes();
|
||||
} // GPTData::ReverseHeaderBytes()
|
||||
|
||||
// IMPORTANT NOTE: This function requires non-reversed mainHeader
|
||||
@@ -2458,6 +2488,14 @@ int SizesOK(void) {
|
||||
cerr << "GPTPart is " << sizeof(GPTPart) << " bytes, should be 128 bytes; aborting!\n";
|
||||
allOK = 0;
|
||||
} // if
|
||||
if (sizeof(GUIDData) != 16) {
|
||||
cerr << "GUIDData is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n";
|
||||
allOK = 0;
|
||||
} // if
|
||||
if (sizeof(PartType) != 16) {
|
||||
cerr << "PartType is " << sizeof(GUIDData) << " bytes, should be 16 bytes; aborting!\n";
|
||||
allOK = 0;
|
||||
} // if
|
||||
// Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware
|
||||
if (IsLittleEndian() == 0) {
|
||||
cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"
|
||||
|
||||
5
gpt.h
5
gpt.h
@@ -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:
|
||||
|
||||
93
gptpart.cc
93
gptpart.cc
@@ -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()
|
||||
|
||||
/***********************************
|
||||
|
||||
24
gptpart.h
24
gptpart.h
@@ -20,6 +20,7 @@
|
||||
#include <sys/types.h>
|
||||
#include "support.h"
|
||||
#include "parttypes.h"
|
||||
#include "guid.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -38,38 +39,37 @@ class GPTPart {
|
||||
// adjusting the data-load operation in GPTData::LoadMainTable() and
|
||||
// GPTData::LoadSecondTableAsMain() and then removing the GPTPart
|
||||
// size check in SizesOK() (in gpt.cc file).
|
||||
struct GUIDData partitionType;
|
||||
struct GUIDData uniqueGUID;
|
||||
PartType partitionType;
|
||||
GUIDData uniqueGUID;
|
||||
uint64_t firstLBA;
|
||||
uint64_t lastLBA;
|
||||
uint64_t attributes;
|
||||
unsigned char name[NAME_SIZE];
|
||||
|
||||
static PartTypes typeHelper;
|
||||
public:
|
||||
GPTPart(void);
|
||||
~GPTPart(void);
|
||||
|
||||
// Simple data retrieval:
|
||||
struct GUIDData GetType(void) {return partitionType;}
|
||||
PartType & GetType(void) {return partitionType;}
|
||||
uint16_t GetHexType(void);
|
||||
string GetNameType(void);
|
||||
struct GUIDData GetUniqueGUID(void) {return uniqueGUID;}
|
||||
string GetTypeName(void);
|
||||
GUIDData GetUniqueGUID(void) {return uniqueGUID;}
|
||||
uint64_t GetFirstLBA(void) {return firstLBA;}
|
||||
uint64_t GetLastLBA(void) {return lastLBA;}
|
||||
uint64_t GetLengthLBA(void);
|
||||
uint64_t GetAttributes(void) {return attributes;}
|
||||
string GetName(void);
|
||||
string GetDescription(void);
|
||||
|
||||
// Simple data assignment:
|
||||
void SetType(struct GUIDData t);
|
||||
void SetType(uint16_t hex) {SetType(typeHelper.IDToGUID(hex));}
|
||||
void SetUniqueGUID(struct GUIDData u) {uniqueGUID = u;}
|
||||
void SetUniqueGUID(int zeroOrRandom);
|
||||
void SetType(PartType t);
|
||||
void SetType(uint16_t hex) {partitionType = hex;}
|
||||
void SetUniqueGUID(GUIDData u) {uniqueGUID = u;}
|
||||
void RandomizeUniqueGUID(void) {uniqueGUID.Randomize();}
|
||||
void SetFirstLBA(uint64_t f) {firstLBA = f;}
|
||||
void SetLastLBA(uint64_t l) {lastLBA = l;}
|
||||
void SetAttributes(uint64_t a) {attributes = a;}
|
||||
void SetName(const string & n);
|
||||
void SetDefaultDescription(void);
|
||||
|
||||
// Additional functions
|
||||
GPTPart & operator=(const GPTPart & orig);
|
||||
|
||||
20
mbr.cc
20
mbr.cc
@@ -39,6 +39,7 @@ MBRData::MBRData(void) {
|
||||
numHeads = MAX_HEADS;
|
||||
numSecspTrack = MAX_SECSPERTRACK;
|
||||
myDisk = NULL;
|
||||
canDeleteMyDisk = 0;
|
||||
EmptyMBR();
|
||||
} // MBRData default constructor
|
||||
|
||||
@@ -50,6 +51,7 @@ MBRData::MBRData(string filename) {
|
||||
numHeads = MAX_HEADS;
|
||||
numSecspTrack = MAX_SECSPERTRACK;
|
||||
myDisk = NULL;
|
||||
canDeleteMyDisk = 0;
|
||||
|
||||
srand((unsigned int) time(NULL));
|
||||
// Try to read the specified partition table, but if it fails....
|
||||
@@ -59,8 +61,12 @@ MBRData::MBRData(string filename) {
|
||||
} // if
|
||||
} // MBRData(string filename) constructor
|
||||
|
||||
// Free space used by myDisk only if that's OK -- sometimes it will be
|
||||
// copied from an outside source, in which case that source should handle
|
||||
// it!
|
||||
MBRData::~MBRData(void) {
|
||||
// delete myDisk;
|
||||
if (canDeleteMyDisk)
|
||||
delete myDisk;
|
||||
} // MBRData destructor
|
||||
|
||||
/**********************
|
||||
@@ -74,8 +80,10 @@ MBRData::~MBRData(void) {
|
||||
int MBRData::ReadMBRData(const string & deviceFilename) {
|
||||
int allOK = 1;
|
||||
|
||||
if (myDisk == NULL)
|
||||
if (myDisk == NULL) {
|
||||
myDisk = new DiskIO;
|
||||
canDeleteMyDisk = 1;
|
||||
} // if
|
||||
if (myDisk->OpenForRead(deviceFilename)) {
|
||||
ReadMBRData(myDisk);
|
||||
} else {
|
||||
@@ -98,8 +106,10 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
|
||||
int err = 1;
|
||||
TempMBR tempMBR;
|
||||
|
||||
if (myDisk != NULL)
|
||||
if ((myDisk != NULL) && (canDeleteMyDisk)) {
|
||||
delete myDisk;
|
||||
canDeleteMyDisk = 0;
|
||||
} // if
|
||||
|
||||
myDisk = theDisk;
|
||||
|
||||
@@ -831,9 +841,9 @@ GPTPart MBRData::AsGPT(int i) {
|
||||
if (lastSector > 0) lastSector--;
|
||||
newPart.SetLastLBA(lastSector);
|
||||
newPart.SetType(((uint16_t) origType) * 0x0100);
|
||||
newPart.SetUniqueGUID(1);
|
||||
newPart.RandomizeUniqueGUID();
|
||||
newPart.SetAttributes(0);
|
||||
newPart.SetName(newPart.GetNameType());
|
||||
newPart.SetName(newPart.GetTypeName());
|
||||
} // if not extended, protective, or non-existent
|
||||
} // if (origPart != NULL)
|
||||
return newPart;
|
||||
|
||||
1
mbr.h
1
mbr.h
@@ -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
|
||||
|
||||
449
parttypes.cc
449
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,13 +188,85 @@ int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
|
||||
allOK = 0;
|
||||
} // if/else
|
||||
return allOK;
|
||||
} // PartTypes::AddType()
|
||||
} // GUID::AddType(const char* variant)
|
||||
|
||||
// Assign a GUID based on my custom 2-byte (16-bit) MBR hex ID variant
|
||||
GUIDData & PartType::operator=(uint16_t ID) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
|
||||
// Assign a default value....
|
||||
GUIDData::operator=("EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); // 0700, Linux/Windows data
|
||||
|
||||
// Now search the type list for a match to the ID....
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if (theItem->MBRType == ID) { // found it!
|
||||
GUIDData::operator=(theItem->GUIDType);
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
cout.setf(ios::uppercase);
|
||||
cout.fill('0');
|
||||
cout << "Exact type match not found for type code ";
|
||||
cout.width(4);
|
||||
cout << hex << ID << "; assigning type code for\n'Linux/Windows data'\n" << dec;
|
||||
cout.fill(' ');
|
||||
} // if (!found)
|
||||
return *this;
|
||||
} // PartType::operator=(uint16_t ID)
|
||||
|
||||
// Return the English description of the partition type (e.g., "Linux/Windows data")
|
||||
string PartType::TypeName(void) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
string typeName;
|
||||
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if (theItem->GUIDType == *this) { // found it!
|
||||
typeName = theItem->name;
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
typeName = "Unknown";
|
||||
} // if (!found)
|
||||
return typeName;
|
||||
} // PartType::TypeName()
|
||||
|
||||
// Return the custom GPT fdisk 2-byte (16-bit) hex code for this GUID partition type
|
||||
// Note that this function ignores entries for which the display variable
|
||||
// is set to 0. This enables control of which values get returned when
|
||||
// there are multiple possibilities, but opens the algorithm up to the
|
||||
// potential for problems should the data in the list be bad.
|
||||
uint16_t PartType::GetHexType() {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
uint16_t theID = 0xFFFF;
|
||||
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if ((theItem->GUIDType == *this) && (theItem->display == 1)) { // found it!
|
||||
theID = theItem->MBRType;
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
theID = 0xFFFF;
|
||||
} // if (!found)
|
||||
return theID;
|
||||
} // PartType::GetHex()
|
||||
|
||||
// Displays the available types and my extended MBR codes for same....
|
||||
// Note: This function assumes an 80-column display. On wider displays,
|
||||
// it stops at under 80 columns; on narrower displays, lines will wrap
|
||||
// in an ugly way.
|
||||
void PartTypes::ShowTypes(void) {
|
||||
void PartType::ShowAllTypes(void) {
|
||||
int colCount = 1; // column count
|
||||
size_t i;
|
||||
AType* thisType = allTypes;
|
||||
@@ -257,10 +289,10 @@ void PartTypes::ShowTypes(void) {
|
||||
} // while
|
||||
cout.fill(' ');
|
||||
cout << "\n" << dec;
|
||||
} // PartTypes::ShowTypes()
|
||||
} // PartType::ShowTypes()
|
||||
|
||||
// Returns 1 if code is a valid extended MBR code, 0 if it's not
|
||||
int PartTypes::Valid(uint16_t code) {
|
||||
int PartType::Valid(uint16_t code) {
|
||||
AType* thisType = allTypes;
|
||||
int found = 0;
|
||||
|
||||
@@ -271,85 +303,4 @@ int PartTypes::Valid(uint16_t code) {
|
||||
thisType = thisType->next;
|
||||
} // while
|
||||
return found;
|
||||
} // PartTypes::Valid()
|
||||
|
||||
// Convert a GUID code to a name.
|
||||
string PartTypes::GUIDToName(struct GUIDData typeCode) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
string typeName;
|
||||
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if ((theItem->GUIDType.data1 == typeCode.data1) &&
|
||||
(theItem->GUIDType.data2 == typeCode.data2)) { // found it!
|
||||
typeName = theItem->name;
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
typeName = "Unknown";
|
||||
} // if (!found)
|
||||
return typeName;
|
||||
} // PartTypes::GUIDToName()
|
||||
|
||||
// This function takes a variant of the MBR partition type code and
|
||||
// converts it to a GUID type code
|
||||
struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
struct GUIDData theGUID;
|
||||
|
||||
// Start by assigning a default GUID for the return value. Done
|
||||
// "raw" to avoid the necessity for a recursive call and the
|
||||
// remote possibility of an infinite recursive loop that this
|
||||
// approach would present....
|
||||
theGUID.data1 = UINT64_C(0x4433B9E5EBD0A0A2);
|
||||
theGUID.data2 = UINT64_C(0xC79926B7B668C087);
|
||||
|
||||
// Now search the type list for a match to the ID....
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if (theItem->MBRType == ID) { // found it!
|
||||
theGUID = theItem->GUIDType;
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
cout.setf(ios::uppercase);
|
||||
cout.fill('0');
|
||||
cout << "Exact type match not found for type code ";
|
||||
cout.width(4);
|
||||
cout << hex << ID << "; assigning type code for\n'Linux/Windows data'\n" << dec;
|
||||
cout.fill(' ');
|
||||
} // if (!found)
|
||||
return theGUID;
|
||||
} // PartTypes::IDToGUID()
|
||||
|
||||
// Convert a GUID to a 16-bit variant of the MBR ID number.
|
||||
// Note that this function ignores entries for which the display variable
|
||||
// is set to 0. This enables control of which values get returned when
|
||||
// there are multiple possibilities, but opens the algorithm up to the
|
||||
// potential for problems should the data in the list be bad.
|
||||
uint16_t PartTypes::GUIDToID(struct GUIDData typeCode) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
uint16_t theID = 0xFFFF;
|
||||
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if ((theItem->GUIDType.data1 == typeCode.data1) &&
|
||||
(theItem->GUIDType.data2 == typeCode.data2) &&
|
||||
(theItem->display == 1)) { // found it!
|
||||
theID = theItem->MBRType;
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
theID = 0xFFFF;
|
||||
} // if (!found)
|
||||
return theID;
|
||||
} // PartTypes::GUIDToID()
|
||||
} // PartType::Valid()
|
||||
|
||||
36
parttypes.h
36
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
|
||||
|
||||
2
sgdisk.8
2
sgdisk.8
@@ -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;
|
||||
|
||||
115
support.cc
115
support.cc
@@ -200,112 +200,19 @@ string BytesToSI(uint64_t size) {
|
||||
return theValue;
|
||||
} // BlocksToSI()
|
||||
|
||||
// Return a plain-text name for a partition type.
|
||||
// Convert a GUID to a string representation, suitable for display
|
||||
// to humans....
|
||||
string GUIDToStr(struct GUIDData theGUID) {
|
||||
unsigned long long blocks[11];
|
||||
char theString[40];
|
||||
// Converts two consecutive characters in the input string into a
|
||||
// number, interpreting the string as a hexadecimal number, starting
|
||||
// at the specified position.
|
||||
unsigned char StrToHex(const string & input, unsigned int position) {
|
||||
unsigned char retval = 0x00;
|
||||
unsigned int temp;
|
||||
|
||||
theString[0] = '\0';;
|
||||
blocks[0] = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF));
|
||||
blocks[1] = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32;
|
||||
blocks[2] = (theGUID.data1 & UINT64_C(0xFFFF000000000000)) >> 48;
|
||||
blocks[3] = (theGUID.data2 & UINT64_C(0x00000000000000FF));
|
||||
blocks[4] = (theGUID.data2 & UINT64_C(0x000000000000FF00)) >> 8;
|
||||
blocks[5] = (theGUID.data2 & UINT64_C(0x0000000000FF0000)) >> 16;
|
||||
blocks[6] = (theGUID.data2 & UINT64_C(0x00000000FF000000)) >> 24;
|
||||
blocks[7] = (theGUID.data2 & UINT64_C(0x000000FF00000000)) >> 32;
|
||||
blocks[8] = (theGUID.data2 & UINT64_C(0x0000FF0000000000)) >> 40;
|
||||
blocks[9] = (theGUID.data2 & UINT64_C(0x00FF000000000000)) >> 48;
|
||||
blocks[10] = (theGUID.data2 & UINT64_C(0xFF00000000000000)) >> 56;
|
||||
sprintf(theString,
|
||||
"%08llX-%04llX-%04llX-%02llX%02llX-%02llX%02llX%02llX%02llX%02llX%02llX",
|
||||
blocks[0], blocks[1], blocks[2], blocks[3], blocks[4], blocks[5],
|
||||
blocks[6], blocks[7], blocks[8], blocks[9], blocks[10]);
|
||||
return theString;
|
||||
} // GUIDToStr()
|
||||
|
||||
// Get a GUID from the user
|
||||
GUIDData GetGUID(void) {
|
||||
unsigned long long part1, part2, part3, part4, part5;
|
||||
int entered = 0;
|
||||
char temp[255], temp2[255];
|
||||
char* junk;
|
||||
GUIDData theGUID;
|
||||
|
||||
cout << "\nA GUID is entered in five segments of from two to six bytes, with\n"
|
||||
<< "dashes between segments.\n";
|
||||
cout << "Enter the entire GUID, a four-byte hexadecimal number for the first segment, or\n"
|
||||
<< "'R' to generate the entire GUID randomly: ";
|
||||
junk = fgets(temp, 255, stdin);
|
||||
|
||||
// If user entered 'r' or 'R', generate GUID randomly....
|
||||
if ((temp[0] == 'r') || (temp[0] == 'R')) {
|
||||
theGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
|
||||
theGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
|
||||
entered = 1;
|
||||
} // if user entered 'R' or 'r'
|
||||
|
||||
// If string length is right for whole entry, try to parse it....
|
||||
if ((strlen(temp) == 37) && (entered == 0)) {
|
||||
strncpy(temp2, &temp[0], 8);
|
||||
temp2[8] = '\0';
|
||||
sscanf(temp2, "%llx", &part1);
|
||||
strncpy(temp2, &temp[9], 4);
|
||||
temp2[4] = '\0';
|
||||
sscanf(temp2, "%llx", &part2);
|
||||
strncpy(temp2, &temp[14], 4);
|
||||
temp2[4] = '\0';
|
||||
sscanf(temp2, "%llx", &part3);
|
||||
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
|
||||
strncpy(temp2, &temp[19], 4);
|
||||
temp2[4] = '\0';
|
||||
sscanf(temp2, "%llx", &part4);
|
||||
strncpy(temp2, &temp[24], 12);
|
||||
temp2[12] = '\0';
|
||||
sscanf(temp2, "%llx", &part5);
|
||||
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
|
||||
((part4 & UINT64_C(0x00000000000000FF)) << 8) +
|
||||
((part5 & UINT64_C(0x0000FF0000000000)) >> 24) +
|
||||
((part5 & UINT64_C(0x000000FF00000000)) >> 8) +
|
||||
((part5 & UINT64_C(0x00000000FF000000)) << 8) +
|
||||
((part5 & UINT64_C(0x0000000000FF0000)) << 24) +
|
||||
((part5 & UINT64_C(0x000000000000FF00)) << 40) +
|
||||
((part5 & UINT64_C(0x00000000000000FF)) << 56);
|
||||
entered = 1;
|
||||
if (input.length() >= (position + 2)) {
|
||||
sscanf(input.substr(position, 2).c_str(), "%x", &temp);
|
||||
retval = (unsigned char) temp;
|
||||
} // if
|
||||
|
||||
// If neither of the above methods of entry was used, use prompted
|
||||
// entry....
|
||||
if (entered == 0) {
|
||||
sscanf(temp, "%llx", &part1);
|
||||
cout << "Enter a two-byte hexadecimal number for the second segment: ";
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part2);
|
||||
cout << "Enter a two-byte hexadecimal number for the third segment: ";
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part3);
|
||||
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
|
||||
cout << "Enter a two-byte hexadecimal number for the fourth segment: ";
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part4);
|
||||
cout << "Enter a six-byte hexadecimal number for the fifth segment: ";
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part5);
|
||||
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
|
||||
((part4 & UINT64_C(0x00000000000000FF)) << 8) +
|
||||
((part5 & UINT64_C(0x0000FF0000000000)) >> 24) +
|
||||
((part5 & UINT64_C(0x000000FF00000000)) >> 8) +
|
||||
((part5 & UINT64_C(0x00000000FF000000)) << 8) +
|
||||
((part5 & UINT64_C(0x0000000000FF0000)) << 24) +
|
||||
((part5 & UINT64_C(0x000000000000FF00)) << 40) +
|
||||
((part5 & UINT64_C(0x00000000000000FF)) << 56);
|
||||
entered = 1;
|
||||
} // if/else
|
||||
cout << "New GUID: " << GUIDToStr(theGUID) << "\n";
|
||||
return theGUID;
|
||||
} // GetGUID()
|
||||
return retval;
|
||||
} // StrToHex()
|
||||
|
||||
// Return 1 if the CPU architecture is little endian, 0 if it's big endian....
|
||||
int IsLittleEndian(void) {
|
||||
|
||||
16
support.h
16
support.h
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user