sgdisk program, misc. bug fixes

This commit is contained in:
srs5694
2010-01-12 18:18:36 -05:00
parent 73ba4794a4
commit ba00fed2ef
14 changed files with 264 additions and 112 deletions

View File

@@ -1,10 +1,16 @@
0.6.0 (1/??/2009):
------------------
- Fixed bug that caused the convert to MBR function to fail.
- Added support for disks with other than 512-byte sectors.
- Created embryonic sgdisk program.
- Fixed bug that caused relative sector numbers entered by users (e.g,
"+128M") to be misinterpreted as from the start of the range rather than
from the default value.
0.5.3 (1/4/2009):
-----------------

View File

@@ -1,8 +1,7 @@
CC=gcc
CXX=g++
#CFLAGS=-O2 -fpack-struct
CFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -fpack-struct -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -g
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I/opt/local/include -g
LIB_NAMES=crc32 support gptpart mbr gpt bsd parttypes attributes
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
@@ -12,11 +11,13 @@ DEPEND= makedepend $(CFLAGS)
#$(APPNAME): $(MBR2GPT_OBJS)
# $(CC) $(MBR2GPT_OBJS) -o $@
all: gdisk sgdisk
gdisk: $(LIB_OBJS) gdisk.o
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -o sgdisk
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -lpopt -o sgdisk
wipegpt: $(LIB_OBJS) wipegpt.o
$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
@@ -25,7 +26,7 @@ lint: #no pre-reqs
lint $(SRCS)
clean: #no pre-reqs
rm -f core *.o *~ gdisk
rm -f core *.o *~ gdisk sgdisk
# what are the source dependencies
depend: $(SRCS)

21
README
View File

@@ -44,11 +44,22 @@ Installing
To compile gdisk, you must have appropriate development tools installed,
most notably the GNU Compiler Collection (GCC) and its g++ compiler for
C++. Uncompress the package and type "make" at the command prompt in the
resulting directory. The result should be a program file called gdisk. You
can use this in place or copy the file to a suitable directory, such as
/usr/local/sbin. You can copy the man page (gdisk.8) to /usr/local/man/man8
to make it available.
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 development libraries. 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.
Caveats
-------

37
bsd.cc
View File

@@ -70,12 +70,15 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
uint32_t* temp32;
uint16_t* temp16;
BSDRecord* tempRecords;
int offset[3] = { LABEL_OFFSET1, LABEL_OFFSET2, LABEL_OFFSET3 };
labelFirstLBA = startSector;
labelLastLBA = endSector;
// Read eight sectors into memory; we'll extract data from
// this buffer. (Done to work around FreeBSD limitation)
// Read 4096 bytes (eight 512-byte sectors or equivalent)
// into memory; we'll extract data from this buffer.
// (Done to work around FreeBSD limitation on size of reads
// from block devices.)
lseek64(fd, startSector * GetBlockSize(fd), SEEK_SET);
err = read(fd, buffer, 4096);
@@ -85,27 +88,23 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
if (bigEnd)
ReverseBytes(&realSig, 4);
// Look for the signature at one of two locations
labelStart = LABEL_OFFSET1;
temp32 = (uint32_t*) &buffer[labelStart];
// Look for the signature at any of three locations.
// Note that the signature is repeated at both the original
// offset and 132 bytes later, so we need two checks....
i = 0;
do {
temp32 = (uint32_t*) &buffer[offset[i]];
signature = *temp32;
if (signature == realSig) {
temp32 = (uint32_t*) &buffer[labelStart + 132];
if (signature == realSig) { // found first, look for second
temp32 = (uint32_t*) &buffer[offset[i] + 132];
signature2 = *temp32;
if (signature2 == realSig)
if (signature2 == realSig) {
foundSig = 1;
labelStart = offset[i];
} // if found signature
} // if/else
if (!foundSig) { // look in second location
labelStart = LABEL_OFFSET2;
temp32 = (uint32_t*) &buffer[labelStart];
signature = *temp32;
if (signature == realSig) {
temp32 = (uint32_t*) &buffer[labelStart + 132];
signature2 = *temp32;
if (signature2 == realSig)
foundSig = 1;
} // if/else
} // if
i++;
} while ((!foundSig) && (i < 3));
// Load partition metadata from the buffer....
temp32 = (uint32_t*) &buffer[labelStart + 40];

12
bsd.h
View File

@@ -13,14 +13,16 @@
#define BSD_SIGNATURE UINT32_C(0x82564557) /* BSD disklabel signature ("magic") */
#define LABEL_OFFSET1 64 /* BSD disklabels can start at one of these two */
#define LABEL_OFFSET2 512 /* values; check both for valid signatures */
#define LABEL_OFFSET1 64 /* BSD disklabels can start at any of these three */
#define LABEL_OFFSET2 512 /* values; check all for valid signatures */
#define LABEL_OFFSET3 2048
// FreeBSD documents a maximum # of partitions of 8, but I saw 16 on a NetBSD
// disk. I'm quadrupling that for further safety. Note that BSDReadData()
// uses a 2048-byte I/O buffer. In combination with LABEL_OFFSET2 and the
// uses a 4096-byte I/O buffer. In combination with LABEL_OFFSET3 and the
// additional 148-byte offset to the actual partition data, that gives a
// theoretical maximum of 86.75 partitions that the program can handle.
// theoretical maximum of 118.75 partitions that the program can handle before
// memory errors will occur.
#define MAX_BSD_PARTS 64
@@ -47,7 +49,7 @@ struct BSDRecord { // the partition table
uint16_t pcpg; // filesystem cylinders per group
};
// Full data in tweaked MBR format
// Full data in tweaked BSD format
class BSDData {
protected:
// We only need a few items from the main BSD disklabel data structure....

13
gdisk.8
View File

@@ -2,7 +2,7 @@
.\" May be distributed under the GNU General Public License
.TH "GDISK" "8" "0.5.3" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- GUID partition table (GPT) manipulator for Linux and Unix
gdisk \- Interactive GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS"
.BI "gdisk "
[ \-l ]
@@ -198,12 +198,12 @@ can be specified in absolute terms as sector numbers or as positions
measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T);
for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of
the disk. You can specify locations relative to the start or end of the
specified range by preceding the number by a '+' or '\-' symbol, as in
\fI\fB+2G\fR\fR to specify a point 2GiB after the first available sector,
specified default range by preceding the number by a '+' or '\-' symbol, as
in \fI\fB+2G\fR\fR to specify a point 2GiB after the default start sector,
or \fI\fB\-200M\fR\fR to specify a point 200MiB before the last available
sector. Pressing the Enter key with no input specifies the default value,
which is the start of the largest available block for the start sector and
the last available block for the end sector.
the end of the same block for the end sector.
.TP
.B o
@@ -532,10 +532,7 @@ should be considered beta software. Known bugs and limitations include:
.B *
The program compiles correctly only on Linux, FreeBSD, and Mac OS X. Linux
versions for x86\-64 (64\-bit), x86 (32\-bit), and PowerPC (32\-bit) have been
tested, with the x86\-64 version having seen the most testing. The Mac OS X
support was added with version 0.3.1 and has not been as thoroughly tested.
FreeBSD support was added with version 0.4.0 and has seen even less
testing.
tested, with the x86\-64 version having seen the most testing.
.TP
.B *

View File

@@ -170,7 +170,7 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
int goOn = 1;
do {
printf("\nrecovery/transformation command (? for help): ");
printf("\nRecovery/transformation command (? for help): ");
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
@@ -313,7 +313,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
} else printf("No partitions\n");
break;
case 'd': case 'D':
printf("The number of logical sectors per physical sector is %d.\n",
printf("Partitions will begin on %d-sector boundaries.\n",
theGPT->GetAlignment());
break;
case 'e': case 'E':
@@ -328,7 +328,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
theGPT->ShowDetails();
break;
case 'l': case 'L':
temp1 = GetNumber(1, 128, 8, "Enter the number of logical sectors in a physical sector on the\ndisk (1-128, default = 8): ");
temp1 = GetNumber(1, 128, 8, "Enter the sector alignment value (1-128, default = 8): ");
theGPT->SetAlignment(temp1);
break;
case 'm': case 'M':
@@ -377,11 +377,11 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
void ShowExpertCommands(void) {
printf("a\tset attributes\n");
printf("c\tchange partition GUID\n");
printf("d\tdisplay the number of logical sectors per physical sector\n");
printf("d\tdisplay the sector alignment value\n");
printf("e\trelocate backup data structures to the end of the disk\n");
printf("g\tchange disk GUID\n");
printf("i\tshow detailed information on a partition\n");
printf("b\tset the number of logical sectors per physical sector\n");
printf("l\tset the sector alignment value\n");
printf("m\treturn to main menu\n");
printf("n\tcreate a new protective MBR\n");
printf("o\tprint protective MBR data\n");

142
gpt.cc
View File

@@ -48,6 +48,8 @@ GPTData::GPTData(void) {
apmFound = 0;
bsdFound = 0;
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
beQuiet = 0;
whichWasUsed = use_new;
srand((unsigned int) time(NULL));
mainHeader.numParts = 0;
SetGPTSize(NUM_GPT_ENTRIES);
@@ -68,6 +70,8 @@ GPTData::GPTData(char* filename) {
apmFound = 0;
bsdFound = 0;
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
beQuiet = 0;
whichWasUsed = use_new;
srand((unsigned int) time(NULL));
mainHeader.numParts = 0;
LoadPartitions(filename);
@@ -499,22 +503,22 @@ int GPTData::FindOverlaps(void) {
// the results.
void GPTData::PartitionScan(int fd) {
BSDData bsdDisklabel;
// int bsdFound;
printf("Partition table scan:\n");
// Read the MBR & check for BSD disklabel
protectiveMBR.ReadMBRData(fd);
protectiveMBR.ShowState();
bsdDisklabel.ReadBSDData(fd, 0, diskSize - 1);
bsdFound = bsdDisklabel.ShowState();
// bsdDisklabel.DisplayBSDData();
// Load the GPT data, whether or not it's valid
ForceLoadGPTData(fd);
if (!beQuiet) {
printf("Partition table scan:\n");
protectiveMBR.ShowState();
bsdDisklabel.ShowState();
ShowAPMState(); // Show whether there's an Apple Partition Map present
ShowGPTState(); // Show GPT status
printf("\n");
} // if
if (apmFound) {
printf("\n*******************************************************************\n");
@@ -549,9 +553,10 @@ int GPTData::LoadPartitions(char* deviceFilename) {
blockSize = (uint32_t) GetBlockSize(fd);
sectorAlignment = FindAlignment(fd);
strcpy(device, deviceFilename);
PartitionScan(fd); // Check for partition types & print summary
PartitionScan(fd); // Check for partition types, load GPT, & print summary
switch (UseWhichPartitions()) {
whichWasUsed = UseWhichPartitions();
switch (whichWasUsed) {
case use_mbr:
XFormPartitions();
break;
@@ -763,7 +768,7 @@ void GPTData::LoadSecondTableAsMain(void) {
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
// write, 0 if there was a problem.
int GPTData::SaveGPTData(void) {
int GPTData::SaveGPTData(int quiet) {
int allOK = 1;
char answer, line[256];
int fd;
@@ -799,7 +804,7 @@ int GPTData::SaveGPTData(void) {
} // if
// Check that second header is properly placed. Warn and ask if this should
// be corrected if the test fails....
if (mainHeader.backupLBA < (diskSize - UINT64_C(1))) {
if ((mainHeader.backupLBA < (diskSize - UINT64_C(1))) && (quiet == 0)) {
printf("Warning! Secondary header is placed too early on the disk! Do you want to\n"
"correct this problem? ");
if (GetYN() == 'Y') {
@@ -833,7 +838,7 @@ int GPTData::SaveGPTData(void) {
} // if
RecomputeCRCs();
if (allOK) {
if ((allOK) && (!quiet)) {
printf("\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n");
printf("MBR PARTITIONS!! THIS PROGRAM IS BETA QUALITY AT BEST. IF YOU LOSE ALL YOUR\n");
printf("DATA, YOU HAVE ONLY YOURSELF TO BLAME IF YOU ANSWER 'Y' BELOW!\n\n");
@@ -1251,10 +1256,7 @@ void GPTData::CreatePartition(void) {
} while (IsFree(sector) == 0);
lastBlock = sector;
partitions[partNum].SetFirstLBA(firstBlock);
partitions[partNum].SetLastLBA(lastBlock);
partitions[partNum].SetUniqueGUID(1);
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
partitions[partNum].ChangeType();
partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType(prompt));
} else {
@@ -1266,21 +1268,12 @@ void GPTData::CreatePartition(void) {
void GPTData::DeletePartition(void) {
int partNum;
uint32_t low, high;
uint64_t startSector, length;
char prompt[255];
if (GetPartRange(&low, &high) > 0) {
sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
partNum = GetNumber(low + 1, high + 1, low, prompt);
// In case there's a protective MBR, look for & delete matching
// MBR partition....
startSector = partitions[partNum - 1].GetFirstLBA();
length = partitions[partNum - 1].GetLengthLBA();
protectiveMBR.DeleteByLocation(startSector, length);
// Now delete the GPT partition
partitions[partNum - 1].BlankPartition();
DeletePartition(partNum - 1);
} else {
printf("No partitions\n");
} // if/else
@@ -1315,6 +1308,8 @@ void GPTData::SetAttributes(uint32_t partNum) {
// user confirms destruction, 0 if the user aborts.
// If prompt == 0, don't ask user about proceeding and do NOT wipe out
// MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.)
// If prompt == -1, don't ask user about proceeding and DO wipe out
// MBR.
int GPTData::DestroyGPT(int prompt) {
int fd, i, sum, tableSize;
char blankSector[512], goOn = 'Y', blank = 'N';
@@ -1324,11 +1319,11 @@ int GPTData::DestroyGPT(int prompt) {
blankSector[i] = '\0';
} // for
if (((apmFound) || (bsdFound)) && prompt) {
if (((apmFound) || (bsdFound)) && (prompt > 0)) {
printf("WARNING: APM or BSD disklabel structures detected! This operation could\n"
"damage any APM or BSD partitions on this disk!\n");
} // if APM or BSD
if (prompt) {
if (prompt > 0) {
printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
goOn = GetYN();
} // if
@@ -1361,16 +1356,16 @@ int GPTData::DestroyGPT(int prompt) {
if (myWrite(fd, blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
} // if
if (prompt) {
if (prompt > 0) {
printf("Blank out MBR? ");
blank = GetYN();
}// if
} // if
// Note on below: Touch the MBR only if the user wants it completely
// blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote
// the MBR, but this could wipe out a valid MBR that the program
// had subsequently discarded (say, if it conflicted with older GPT
// structures).
if (blank == 'Y') {
if ((blank == 'Y') || (prompt < 0)) {
lseek64(fd, 0, SEEK_SET);
if (myWrite(fd, blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
@@ -1681,6 +1676,7 @@ int GPTData::XFormToMBR(void) {
printf("\nCreating entry for partition #%d\n", j + 1);
numConverted += OnePartToMBR(j, i);
} // for
printf("MBR writing returned %d\n", protectiveMBR.WriteMBRData(device));
return numConverted;
} // GPTData::XFormToMBR()
@@ -1774,7 +1770,8 @@ void GPTData::MakeHybrid(void) {
**********************************************************************/
// Resizes GPT to specified number of entries. Creates a new table if
// necessary, copies data if it already exists.
// necessary, copies data if it already exists. Returns 1 if all goes
// well, 0 if an error is encountered.
int GPTData::SetGPTSize(uint32_t numEntries) {
struct GPTPart* newParts;
struct GPTPart* trash;
@@ -1844,6 +1841,51 @@ void GPTData::BlankPartitions(void) {
} // for
} // GPTData::BlankPartitions()
// Delete a partition by number. Returns 1 if successful,
// 0 if there was a problem. Returns 1 if partition was in
// range, 0 if it was out of range.
int GPTData::DeletePartition(uint32_t partNum) {
uint64_t startSector, length;
uint32_t low, high, numParts, retval = 1;;
numParts = GetPartRange(&low, &high);
if ((numParts > 0) && (partNum >= low) && (partNum <= high)) {
// In case there's a protective MBR, look for & delete matching
// MBR partition....
startSector = partitions[partNum].GetFirstLBA();
length = partitions[partNum].GetLengthLBA();
protectiveMBR.DeleteByLocation(startSector, length);
// Now delete the GPT partition
partitions[partNum].BlankPartition();
} else {
fprintf(stderr, "Partition number %d out of range!\n", partNum + 1);
retval = 0;
} // if/else
return retval;
} // GPTData::DeletePartition(uint32_t partNum)
// Non-interactively create a partition. Note that this function is overloaded
// with another of the same name but different parameters; that one prompts
// the user for data. This one returns 1 if the operation was successful, 0
// if a problem was discovered.
int GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) {
int retval = 1; // assume there'll be no problems
if (IsFreePartNum(partNum)) {
Align(&startSector); // Align sector to correct multiple
if (IsFree(startSector) && (startSector <= endSector)) {
if (FindLastInFree(startSector) >= endSector) {
partitions[partNum].SetFirstLBA(startSector);
partitions[partNum].SetLastLBA(endSector);
partitions[partNum].SetType(0x0700);
partitions[partNum].SetUniqueGUID(1);
} else retval = 0; // if free space until endSector
} else retval = 0; // if startSector is free
} else retval = 0; // if legal partition number
return retval;
} // GPTData::CreatePartition(partNum, startSector, endSector)
// Sort the GPT entries, eliminating gaps and making for a logical
// ordering. Relies on QuickSortGPT() for the bulk of the work
void GPTData::SortGPT(void) {
@@ -1934,10 +1976,13 @@ void GPTData::MoveSecondHeaderToEnd() {
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
} // GPTData::FixSecondHeaderLocation()
void GPTData::SetName(uint32_t partNum, char* theName) {
if ((partNum >= 0) && (partNum < mainHeader.numParts))
if (partitions[partNum].GetFirstLBA() > 0)
int GPTData::SetName(uint32_t partNum, char* theName) {
int retval = 1;
if (!IsFreePartNum(partNum))
partitions[partNum].SetName((unsigned char*) theName);
else retval = 0;
return retval;
} // GPTData::SetName
// Set the disk GUID to the specified value. Note that the header CRCs must
@@ -1962,6 +2007,17 @@ int GPTData::SetPartitionGUID(uint32_t pn, GUIDData theGUID) {
return retval;
} // GPTData::SetPartitionGUID()
// Change partition type code non-interactively. Returns 1 if
// successful, 0 if not....
int GPTData::ChangePartType(uint32_t partNum, uint16_t hexCode) {
int retval = 1;
if (!IsFreePartNum(partNum)) {
partitions[partNum].SetType(hexCode);
} else retval = 0;
return retval;
} // GPTData::ChangePartType()
// Adjust sector number so that it falls on a sector boundary that's a
// multiple of sectorAlignment. This is done to improve the performance
// of Western Digital Advanced Format disks and disks with similar
@@ -2015,8 +2071,10 @@ int GPTData::Align(uint64_t* sector) {
// Otherwise, notify the user that it couldn't be done....
if (sectorOK == 1) {
printf("Information: Moved requested sector from %llu to %llu for\n"
"alignment purposes. Use 'l' on the experts' menu to adjust alignment.\n",
"alignment purposes.\n",
(unsigned long long) original, (unsigned long long) *sector);
if (!beQuiet)
printf("Use 'l' on the experts' menu to adjust alignment\n");
} else {
printf("Information: Sector not aligned on %d-sector boundary and could not be moved.\n"
"If you're using a Western Digital Advanced Format or similar disk with\n"
@@ -2227,6 +2285,20 @@ int GPTData::IsFree(uint64_t sector) {
return (isFree);
} // GPTData::IsFree()
// Returns 1 if partNum is unused.
int GPTData::IsFreePartNum(uint32_t partNum) {
int retval = 1;
if ((partNum >= 0) && (partNum < mainHeader.numParts)) {
if ((partitions[partNum].GetFirstLBA() != UINT64_C(0)) ||
(partitions[partNum].GetLastLBA() != UINT64_C(0))) {
retval = 0;
} // if partition is in use
} else retval = 0;
return retval;
} // GPTData::IsFreePartNum()
/********************************
* *
* Endianness support functions *

23
gpt.h
View File

@@ -32,6 +32,7 @@ enum GPTValidity {gpt_valid, gpt_corrupt, gpt_invalid};
enum WhichToUse {use_gpt, use_mbr, use_bsd, use_new};
// Header (first 512 bytes) of GPT table
#pragma pack(1)
struct GPTHeader {
uint64_t signature;
uint32_t revision;
@@ -54,7 +55,7 @@ struct GPTHeader {
class GPTData {
protected:
struct GPTHeader mainHeader;
struct GPTPart *partitions;
GPTPart *partitions;
struct GPTHeader secondHeader;
MBRData protectiveMBR;
char device[256]; // device filename
@@ -70,6 +71,8 @@ protected:
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:
// Basic necessary functions....
GPTData(void);
@@ -94,7 +97,7 @@ public:
int ForceLoadGPTData(int fd);
int LoadMainTable(void);
void LoadSecondTableAsMain(void);
int SaveGPTData(void);
int SaveGPTData(int quiet = 0);
int SaveGPTBackup(char* filename);
int LoadGPTBackup(char* filename);
@@ -127,16 +130,17 @@ public:
// Adjust GPT structures WITHOUT user interaction...
int SetGPTSize(uint32_t numEntries);
void BlankPartitions(void);
int DeletePartition(uint32_t partNum);
int CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector);
void SortGPT(void);
int ClearGPTData(void);
void MoveSecondHeaderToEnd();
void SetName(uint32_t partNum, char* theName = NULL);
int SetName(uint32_t partNum, char* theName = NULL);
void SetDiskGUID(GUIDData newGUID);
int SetPartitionGUID(uint32_t pn, GUIDData theGUID);
int ChangePartType(uint32_t pn, uint16_t hexCode);
void MakeProtectiveMBR(void) {protectiveMBR.MakeProtectiveMBR();}
int Align(uint64_t* sector);
void SetAlignment(int n) {sectorAlignment = n;}
void JustLooking(int i = 1) {justLooking = i;}
// Return data about the GPT structures....
int GetPartRange(uint32_t* low, uint32_t* high);
@@ -146,7 +150,6 @@ public:
uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
uint32_t CountParts(void);
int GetAlignment(void) {return sectorAlignment;}
// Find information about free space
uint64_t FindFirstAvailable(uint64_t start = 0);
@@ -155,6 +158,14 @@ public:
uint64_t FindLastInFree(uint64_t start);
uint64_t FindFreeBlocks(int *numSegments, uint64_t *largestSegment);
int IsFree(uint64_t sector);
int IsFreePartNum(uint32_t partNum);
// Change how functions work, or return information on same
void SetAlignment(int n) {sectorAlignment = n;}
int GetAlignment(void) {return sectorAlignment;}
void JustLooking(int i = 1) {justLooking = i;}
void BeQuiet(int i = 1) {beQuiet = i;}
WhichToUse WhichWasUsed(void) {return whichWasUsed;}
// Endianness functions
void ReverseHeaderBytes(struct GPTHeader* header); // for endianness

View File

@@ -206,7 +206,7 @@ void GPTPart::ChangeType(void) {
else // user wants to enter the GUID directly, so do that
newType = GetGUID();
partitionType = newType;
printf("Changed system type of partition to '%s'\n",
printf("Changed type of partition to '%s'\n",
typeHelper.GUIDToName(partitionType, typeName));
} // GPTPart::ChangeType()
@@ -278,4 +278,3 @@ void QuickSortGPT(GPTPart* partitions, int start, int finish) {
if (start < right) QuickSortGPT(partitions, start, right);
if (finish > left) QuickSortGPT(partitions, left, finish);
} // QuickSortGPT()

View File

@@ -31,13 +31,13 @@ using namespace std;
class GPTPart {
protected:
// Caution: The non-static data in GUIDPart is precisely the right size
// Caution: The non-static data in GPTPart is precisely the right size
// to enable easy loading of the data directly from disk. If any
// non-static variables are added to the below, the data size will
// change and the program will stop working. This can be corrected by
// adjusting the data-load operation in GPTData::LoadMainTable() and
// GPTData::LoadSecondTableAsMain() and then removing the GUIDPart
// size check in SizesOK().
// GPTData::LoadSecondTableAsMain() and then removing the GPTPart
// size check in SizesOK() (in gpt.cc file).
struct GUIDData partitionType;
struct GUIDData uniqueGUID;
uint64_t firstLBA;

5
mbr.cc
View File

@@ -305,6 +305,11 @@ void MBRData::WriteMBRData(int fd) {
}// if
} // MBRData::WriteMBRData(int fd)
int MBRData::WriteMBRData(char* deviceFilename) {
strcpy(device, deviceFilename);
return WriteMBRData();
} // MBRData::WriteMBRData(char* deviceFilename)
/********************************************
* *
* Functions that display data for the user *

7
mbr.h
View File

@@ -30,6 +30,7 @@ using namespace std;
// Data for a single MBR partition record
// Note that firstSector and lastSector are in CHS addressing, which
// splits the bits up in a weird way.
#pragma pack(1)
struct MBRRecord {
uint8_t status;
uint8_t firstSector[3];
@@ -43,6 +44,7 @@ struct MBRRecord {
// go, for the benefit of FreeBSD which seems to flake out when loading
// from block devices in multiples other than the block size.
// Also used when loading logical partitions.
#pragma pack(1)
struct TempMBR {
uint8_t code[440];
uint32_t diskSignature;
@@ -81,12 +83,13 @@ public:
// File I/O functions...
int ReadMBRData(char* deviceFilename);
void ReadMBRData(int fd, int checkBlockSize = 1);
// ReadLogicalPart() returns last partition # read to logicals[] array,
// or -1 if there was a problem....
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
int partNum);
int WriteMBRData(void);
void WriteMBRData(int fd);
// ReadLogicalPart() returns last partition # read to logicals[] array,
// or -1 if there was a problem....
int WriteMBRData(char* deviceFilename);
// Display data for user...
void DisplayMBRData(void);

View File

@@ -27,6 +27,10 @@
#define BLKPBSZGET _IO(0x12,123)
#endif
// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
// cutoff
#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
using namespace std;
// Get a numeric value from the user, between low and high (inclusive).
@@ -84,8 +88,7 @@ char GetYN(void) {
//value as the default if the user just hits Enter
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[]) {
unsigned long long response;
int num;
int plusFlag = 0;
int num, plusFlag = 0;
uint64_t mult = 1;
char suffix;
char line[255];
@@ -147,7 +150,14 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[])
// Adjust response based on multiplier and plus flag, if present
response *= (unsigned long long) mult;
if (plusFlag == 1) {
// Recompute response based on low part of range (if default = high
// value, which should be the case when prompting for the end of a
// range) or the defaut value (if default != high, which should be
// the case for the first sector of a partition).
if (def == high)
response = response + (unsigned long long) low - UINT64_C(1);
else
response = response + (unsigned long long) def - UINT64_C(1);
} // if
if (plusFlag == -1) {
response = (unsigned long long) high - response;
@@ -231,29 +241,65 @@ int GetBlockSize(int fd) {
return (result);
} // GetBlockSize()
// My original FindAlignment() function (after this one) isn't working, since
// the BLKPBSZGET ioctl() isn't doing what I expected (it returns 512 even on
// a WD Advanced Format drive). Therefore, I'm using a simpler function that
// returns 1-sector alignment for unusual sector sizes and drives smaller than
// a size defined by SMALLEST_ADVANCED_FORMAT, and 8-sector alignment for
// larger drives with 512-byte sectors.
int FindAlignment(int fd) {
int err, result;
if ((GetBlockSize(fd) == 512) && (disksize(fd, &err) >= SMALLEST_ADVANCED_FORMAT)) {
result = 8; // play it safe; align for 4096-byte sectors
} else {
result = 1; // unusual sector size; assume it's the real physical size
} // if/else
return result;
} // FindAlignment
// Return the partition alignment value in sectors. Right now this works
// only for Linux 2.6.32 and later, since I can't find equivalent ioctl()s
// for OS X or FreeBSD, and the Linux ioctl is new
int FindAlignment(int fd) {
int err = -2, result = 8, physicalSectorSize = 4096;
/* int FindAlignment(int fd) {
int err = -2, errnum = 0, result = 8, physicalSectorSize = 4096;
uint64_t diskSize;
printf("Entering FindAlignment()\n");
#if defined (__linux__) && defined (BLKPBSZGET)
err = ioctl(fd, BLKPBSZGET, &physicalSectorSize);
printf("In FindAlignment(), physicalSectorSize = %d, err = %d\n", physicalSectorSize, err);
// printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize);
#else
err = -1;
#endif
if (err < 0) { // ioctl didn't work; have to guess....
if (GetBlockSize(fd) == 512)
if (GetBlockSize(fd) == 512) {
result = 8; // play it safe; align for 4096-byte sectors
else
} else {
result = 1; // unusual sector size; assume it's the real physical size
} // if/else
} else { // ioctl worked; compute alignment
result = physicalSectorSize / GetBlockSize(fd);
// Disks with larger physical than logical sectors must theoretically
// have a total disk size that's a multiple of the physical sector
// size; however, some such disks have compatibility jumper settings
// meant for one-partition MBR setups, and these reduce the total
// number of sectors by 1. If such a setting is used, it'll result
// in improper alignment, so look for this condition and warn the
// user if it's found....
diskSize = disksize(fd, &errnum);
if ((diskSize % (uint64_t) result) != 0) {
fprintf(stderr, "\aWarning! Disk size (%llu) is not a multiple of alignment\n"
"size (%d), but it should be! Check disk manual and jumper settings!\n",
(unsigned long long) diskSize, result);
} // if
} // if/else
if (result <= 0) // can happen if physical sector size < logical sector size
result = 1;
return result;
} // FindAlignment(int)
} // FindAlignment(int) */
// The same as FindAlignment(int), but opens and closes a device by filename
int FindAlignment(char deviceFilename[]) {