Version 0.5.3 changes. Minor bug fixes & detection of the number of

logical sectors per physical sector on Linux 2.6.32 and above.
This commit is contained in:
srs5694
2010-01-03 20:57:08 -05:00
parent 1d1448a82d
commit 5d58fe0ea1
10 changed files with 238 additions and 124 deletions

View File

@@ -1,3 +1,20 @@
0.5.3 (1/??/2009):
------------------
- Fixed bug in display of GUIDs when compiled with some versions of GCC.
- Eliminated warnings caused by additional checks in latest versions of
GCC. These warnings were harmless, but to eliminate them I've added
more error checking on disk I/O.
- Eliminated unnecessary warnings about potential data loss if the program
was launched with the -l option or if writes aren't possible.
- Added code to set the partition boundary value based on the physical
sector size. (FindAlignment() function.) This function, however, works
only on Linux, and then only if the BLKPBSZGET ioctl is defined. This
ioctl is new in kernel 2.6.32 or thereabouts.
0.5.2 (12/31/2009):
-------------------

27
README
View File

@@ -53,23 +53,22 @@ to make it available.
Caveats
-------
THIS SOFTWARE IS EARLY BETA SOFTWARE! IF IT WIPES OUT YOUR HARD DISK OR
EATS YOUR CAT, DON'T BLAME ME! To date, I've tested the software mainly on
two USB flash drives, 2 GiB and 8 GiB in size. I've also made a few minor
tweaks to a production system with a 500 GiB hard disk and made more
extensive changes to a handful of 80-160 GiB hard disks. I believe all
data-corruption bugs to be squashed, but I know full well that the odds of
my missing something are high. This is particularly true for large drives;
I have no way of testing the software with > 2TiB drives, which will test
the 64-bit sector pointer support. I've received user reports of success
with >2TiB drives, though.
THIS SOFTWARE IS BETA SOFTWARE! IF IT WIPES OUT YOUR HARD DISK OR EATS YOUR
CAT, DON'T BLAME ME! To date, I've tested the software on several USB flash
drives, a handful of PATA and SATA hard disks, and several virtual disks in
a QEMU environment. I believe all data-corruption bugs to be squashed, but
I know full well that the odds of my missing something are high. This is
particularly true for large drives; my only direct testing with such disks
is with virtual QEMU disks. I've received user reports of success with
RAID arrays over 2TiB in size, though.
My main development platform is a system running the 64-bit version of
Ubuntu 8.04. I've also tested on 64-bit OpenSuSE, 32-bit Fedora 10, 32-bit
Ubuntu 6.10, 64-bit Gentoo, 32-bit PowerPC Linux, 32-bit Intel-based Mac
OS X, and 64-bit Fedora 7.1. Problems relating to 64-bit integers on the
32-bit Linux have been common during development and may crop up in the
future. The Mac OS X, FreeBSD, and big-endian (PowerPC) support are new.
Fedora 11, 32-bit Ubuntu 6.10, 64-bit Ubunut 9.10, 64-bit Gentoo, 32-bit
PowerPC Debian Linux, 32-bit Intel-based Mac OS X 10.5 and 10.6, and 64-bit
FreeBSD 7.1. Problems relating to 64-bit integers on the 32-bit Linux have
been common during development and may crop up in the future. The Mac OS X,
FreeBSD, and big-endian (PowerPC) support are new.
Redistribution
--------------

18
gdisk.8
View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH "GDISK" "8" "0.5.1" "Roderick W. Smith" "GPT fdisk Manual"
.TH "GDISK" "8" "0.5.3" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS"
@@ -420,9 +420,9 @@ not in \fBgdisk\fR) or sheer incredible coincidence.
.B d
Display the number of logical sectors per physical sector. This value
determines the sector alignment that GPT fdisk enforces. See the
description of the 'l' option for more details. Note that this value
is not actually detected on a disk-by-disk basis; it's set to 8 as a
blanket default.
description of the 'l' option for more details. Note that this value is
only auto-detected on Linux with a 2.6.32 kernel or later; on other
platforms, it defaults to 8.
.TP
.B e
@@ -453,10 +453,10 @@ mid-physical-sector, though, performance can suffer on such drives, since
important filesystem data structures can span physical sectors on the disk.
To minimize such problems, GPT fdisk aligns the start of partitions on the
boundary of presumed physical sectors. You can set the number of logical
sectors per physical sector with this option. The default is 8, which is
set blindly; GPT fdisk does not currently read this information from the
disk. The default value will result in a tiny amount of wasted disk space
on older disks with true 512-byte sectors but will otherwise be harmless.
sectors per physical sector with this option. The default is 8, except on
Linux 2.6.32 and later, in which case it's read from the disk. A value of 8
will result in a tiny amount of wasted disk space on older disks with true
512-byte sectors but will otherwise be harmless.
.TP
.B m
@@ -525,7 +525,7 @@ entering data. When only one option is possible, \fBgdisk\fR
usually bypasses the prompt entirely.
.SH "BUGS"
As of November 2009 (version 0.5.1), \fBgdisk\fR
As of January 2010 (version 0.5.3), \fBgdisk\fR
should be considered beta software. Known bugs and limitations include:
.TP

View File

@@ -29,7 +29,7 @@ int main(int argc, char* argv[]) {
int doMore = 1;
char* device = NULL;
printf("GPT fdisk (gdisk) version 0.5.2\n\n");
printf("GPT fdisk (gdisk) version 0.5.3\n\n");
if (argc == 2) { // basic usage
if (SizesOK()) {
@@ -48,6 +48,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
} // if/elseif/else
if (device != NULL) {
theGPT.JustLooking();
doMore = theGPT.LoadPartitions(device);
if (doMore) theGPT.DisplayGPTData();
} // if
@@ -61,19 +62,20 @@ int main(int argc, char* argv[]) {
// wants to exit (such as after a 'w' or 'q' command).
void MainMenu(char* filename, struct GPTData* theGPT) {
char command, line[255], buFile[255];
char* junk;
int goOn = 1;
PartTypes typeHelper;
uint32_t temp1, temp2;
do {
printf("\nCommand (? for help): ");
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
case 'b': case 'B':
printf("Enter backup filename to save: ");
fgets(line, 255, stdin);
sscanf(line, "%s", &buFile);
junk = fgets(line, 255, stdin);
sscanf(line, "%s", (char*) &buFile);
theGPT->SaveGPTBackup(buFile);
break;
case 'c': case 'C':
@@ -163,13 +165,14 @@ void ShowCommands(void) {
// issues an exit command, such as 'w' or 'q'.
void RecoveryMenu(char* filename, struct GPTData* theGPT) {
char command, line[255], buFile[255];
char* junk;
PartTypes typeHelper;
uint32_t temp1;
int goOn = 1;
do {
printf("\nrecovery/transformation command (? for help): ");
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
case 'b': case 'B':
@@ -222,8 +225,8 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
break;
case 'l': case 'L':
printf("Enter backup filename to load: ");
fgets(line, 255, stdin);
sscanf(line, "%s", &buFile);
junk = fgets(line, 255, stdin);
sscanf(line, "%s", (char*) &buFile);
theGPT->LoadGPTBackup(buFile);
break;
case 'm': case 'M':
@@ -286,6 +289,7 @@ void ShowRecoveryCommands(void) {
// selects an exit command, such as 'w' or 'q'.
void ExpertsMenu(char* filename, struct GPTData* theGPT) {
char command, line[255];
char* junk;
PartTypes typeHelper;
uint32_t pn;
uint32_t temp1, temp2;
@@ -293,7 +297,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
do {
printf("\nExpert command (? for help): ");
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
case 'a': case 'A':
@@ -310,7 +314,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 set to %d.\n",
printf("The number of logical sectors per physical sector is %d.\n",
theGPT->GetAlignment());
break;
case 'e': case 'E':

151
gpt.cc
View File

@@ -40,6 +40,7 @@ GPTData::GPTData(void) {
partitions = NULL;
state = gpt_valid;
strcpy(device, "");
justLooking = 0;
mainCrcOk = 0;
secondCrcOk = 0;
mainPartsCrcOk = 0;
@@ -58,6 +59,7 @@ GPTData::GPTData(char* filename) {
partitions = NULL;
state = gpt_invalid;
strcpy(device, "");
justLooking = 0;
mainCrcOk = 0;
secondCrcOk = 0;
mainPartsCrcOk = 0;
@@ -296,7 +298,7 @@ int GPTData::CheckHeaderValidity(void) {
} else if ((mainHeader.revision != 0x00010000) && valid) {
valid -= 1;
printf("Unsupported GPT version in main header; read 0x%08lX, should be\n0x%08lX\n",
(unsigned long) mainHeader.revision, UINT32_C(0x00010000));
(unsigned long) mainHeader.revision, (unsigned long) UINT32_C(0x00010000));
} // if/else/if
if (secondHeader.signature != GPT_SIGNATURE) {
@@ -306,7 +308,7 @@ int GPTData::CheckHeaderValidity(void) {
} else if ((secondHeader.revision != 0x00010000) && valid) {
valid -= 2;
printf("Unsupported GPT version in backup header; read 0x%08lX, should be\n0x%08lX\n",
(unsigned long) mainHeader.revision, UINT32_C(0x00010000));
(unsigned long) mainHeader.revision, (unsigned long) UINT32_C(0x00010000));
} // if/else/if
// If MBR bad, check for an Apple disk signature
@@ -515,7 +517,9 @@ void GPTData::PartitionScan(int fd) {
if (apmFound) {
printf("\n*******************************************************************\n");
printf("This disk appears to contain an Apple-format (APM) partition table!\n");
printf("It will be destroyed if you continue!\n");
if (!justLooking) {
printf("It will be destroyed if you continue!\n");
} // if
printf("*******************************************************************\n\n\a");
} // if
} // GPTData::PartitionScan()
@@ -529,16 +533,19 @@ int GPTData::LoadPartitions(char* deviceFilename) {
// First, do a test to see if writing will be possible later....
fd = OpenForWrite(deviceFilename);
if (fd == -1)
if ((fd == -1) && (!justLooking)) {
printf("\aNOTE: Write test failed with error number %d. It will be "
"impossible to save\nchanges to this disk's partition table!\n\n",
errno);
justLooking = 1;
} // if
close(fd);
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
// store disk information....
diskSize = disksize(fd, &err);
blockSize = (uint32_t) GetBlockSize(fd);
sectorAlignment = FindAlignment(fd);
strcpy(device, deviceFilename);
PartitionScan(fd); // Check for partition types & print summary
@@ -595,7 +602,9 @@ int GPTData::ForceLoadGPTData(int fd) {
// Seek to and read the main GPT header
lseek64(fd, 512, SEEK_SET);
read(fd, &mainHeader, 512); // read main GPT header
if (read(fd, &mainHeader, 512) != 512) { // read main GPT header
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
} // if
mainCrcOk = CheckHeaderCRC(&mainHeader);
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
ReverseHeaderBytes(&mainHeader);
@@ -620,7 +629,9 @@ int GPTData::ForceLoadGPTData(int fd) {
} // if/else (mainCrcOk)
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
read(fd, &secondHeader, 512); // read secondary GPT header
if (read(fd, &secondHeader, 512) != 512) { // read secondary GPT header
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
} // if
secondCrcOk = CheckHeaderCRC(&secondHeader);
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
ReverseHeaderBytes(&secondHeader);
@@ -628,7 +639,7 @@ int GPTData::ForceLoadGPTData(int fd) {
allOK = 0;
state = gpt_invalid;
fprintf(stderr, "Unable to seek to secondary GPT header at sector %llu!\n",
diskSize - (UINT64_C(1)));
(unsigned long long) (diskSize - (UINT64_C(1))));
} // if/else lseek
// Return valid headers code: 0 = both headers bad; 1 = main header
@@ -670,7 +681,9 @@ int GPTData::ForceLoadGPTData(int fd) {
if ((lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) && (secondCrcOk)) {
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
storage = (char*) malloc(sizeOfParts);
read(fd, storage, sizeOfParts);
if (read(fd, storage, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Error %d reading backup partition table!\n", errno);
} // if
newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
free(storage);
secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
@@ -703,7 +716,9 @@ int GPTData::LoadMainTable(void) {
// matches the stored value
lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET);
sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
read(fd, partitions, sizeOfParts);
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Error %d when loading the main partition table!\n", errno);
} // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
if (IsLittleEndian() == 0)
@@ -725,7 +740,9 @@ void GPTData::LoadSecondTableAsMain(void) {
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
SetGPTSize(secondHeader.numParts);
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
read(fd, partitions, sizeOfParts);
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Read error %d! Misbehavior now likely!\n", errno);
} // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
mainPartsCrcOk = secondPartsCrcOk;
@@ -757,6 +774,13 @@ int GPTData::SaveGPTData(void) {
} // if
// First do some final sanity checks....
// This test should only fail on read-only disks....
if (justLooking) {
printf("The justLooking flag is set. This probably means you can't write to the disk.\n");
allOK = 0;
} // if
// Is there enough space to hold the GPT headers and partition tables,
// given the partition sizes?
if (CheckGPTSize() > 0) {
@@ -767,8 +791,8 @@ int GPTData::SaveGPTData(void) {
if (mainHeader.backupLBA > diskSize) {
fprintf(stderr, "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n"
"problem (or it might not). Aborting!\n");
printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n", diskSize,
mainHeader.backupLBA);
printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n",
(unsigned long long) diskSize, (unsigned long long) mainHeader.backupLBA);
allOK = 0;
} // if
// Check that second header is properly placed. Warn and ask if this should
@@ -811,11 +835,10 @@ int GPTData::SaveGPTData(void) {
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");
printf("Do you want to proceed, possibly destroying your data? (Y/N) ");
fgets(line, 255, stdin);
sscanf(line, "%c", &answer);
if ((answer == 'Y') || (answer == 'y')) {
printf("OK; writing new GPT partition table.\n");
printf("Do you want to proceed, possibly destroying your data? ");
answer = GetYN();
if (answer == 'Y') {
printf("OK; writing new GUID partition table (GPT).\n");
} else {
allOK = 0;
} // if/else
@@ -974,7 +997,9 @@ int GPTData::LoadGPTBackup(char* filename) {
// Load the main GPT header, check its vaility, and set the GPT
// size based on the data
read(fd, &mainHeader, 512);
if (read(fd, &mainHeader, 512)) {
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if
mainCrcOk = CheckHeaderCRC(&mainHeader);
// Reverse byte order, if necessary
@@ -984,7 +1009,9 @@ int GPTData::LoadGPTBackup(char* filename) {
// Load the backup GPT header in much the same way as the main
// GPT header....
read(fd, &secondHeader, 512);
if (read(fd, &secondHeader, 512) != 512) {
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if
secondCrcOk = CheckHeaderCRC(&secondHeader);
// Reverse byte order, if necessary
@@ -1018,7 +1045,9 @@ int GPTData::LoadGPTBackup(char* filename) {
// Load main partition table, and record whether its CRC
// matches the stored value
sizeOfParts = numParts * sizeOfEntries;
read(fd, partitions, sizeOfParts);
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
@@ -1082,11 +1111,11 @@ void GPTData::DisplayGPTData(void) {
(unsigned long long) diskSize, sizeInSI);
printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr));
printf("Partition table holds up to %lu entries\n", (unsigned long) mainHeader.numParts);
printf("First usable sector is %lu, last usable sector is %lu\n",
(unsigned long) mainHeader.firstUsableLBA,
(unsigned long) mainHeader.lastUsableLBA);
printf("First usable sector is %llu, last usable sector is %llu\n",
(unsigned long long) mainHeader.firstUsableLBA,
(unsigned long long) mainHeader.lastUsableLBA);
totalFree = FindFreeBlocks(&i, &temp);
printf("Total free space is %llu sectors (%s)\n", totalFree,
printf("Total free space is %llu sectors (%s)\n", (unsigned long long) totalFree,
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
for (i = 0; i < mainHeader.numParts; i++) {
@@ -1189,9 +1218,9 @@ void GPTData::CreatePartition(void) {
} while (partitions[partNum].GetFirstLBA() != 0);
// Get first block for new partition...
sprintf(prompt,
"First sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
firstBlock, lastBlock, firstInLargest);
sprintf(prompt, "First sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
(unsigned long long) firstBlock, (unsigned long long) lastBlock,
(unsigned long long) firstInLargest);
do {
sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt);
} while (IsFree(sector) == 0);
@@ -1200,9 +1229,9 @@ void GPTData::CreatePartition(void) {
// Get last block for new partitions...
lastBlock = FindLastInFree(firstBlock);
sprintf(prompt,
"Last sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
firstBlock, lastBlock, lastBlock);
sprintf(prompt, "Last sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
(unsigned long long) firstBlock, (unsigned long long) lastBlock,
(unsigned long long) lastBlock);
do {
sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt);
} while (IsFree(sector) == 0);
@@ -1273,7 +1302,7 @@ void GPTData::SetAttributes(uint32_t partNum) {
// 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.)
int GPTData::DestroyGPT(int prompt) {
int fd, i;
int fd, i, sum;
char blankSector[512], goOn = 'Y', blank = 'N';
for (i = 0; i < 512; i++) {
@@ -1298,15 +1327,25 @@ int GPTData::DestroyGPT(int prompt) {
#endif
if (fd != -1) {
lseek64(fd, mainHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
write(fd, blankSector, 512); // blank it out
if (write(fd, blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! GPT main header not overwritten! Error is %d\n", errno);
} // if
lseek64(fd, mainHeader.partitionEntriesLBA * 512, SEEK_SET); // seek to partition table
sum = 0;
for (i = 0; i < GetBlocksInPartTable(); i++)
write(fd, blankSector, 512);
sum += write(fd, blankSector, 512);
if (sum != 512 * GetBlocksInPartTable())
fprintf(stderr, "Warning! GPT main partition table not overwritten! Error is %d\n", errno);
lseek64(fd, secondHeader.partitionEntriesLBA * 512, SEEK_SET); // seek to partition table
sum = 0;
for (i = 0; i < GetBlocksInPartTable(); i++)
write(fd, blankSector, 512);
sum += write(fd, blankSector, 512);
if (sum != 512 * GetBlocksInPartTable())
fprintf(stderr, "Warning! GPT backup partition table not overwritten! Error is %d\n", errno);
lseek64(fd, secondHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
write(fd, blankSector, 512); // blank it out
if (write(fd, blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
} // if
if (prompt) {
printf("Blank out MBR? ");
blank = GetYN();
@@ -1318,7 +1357,9 @@ int GPTData::DestroyGPT(int prompt) {
// structures).
if (blank == 'Y') {
lseek64(fd, 0, SEEK_SET);
write(fd, blankSector, 512); // blank it out
if (write(fd, blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
} // if
} else {
printf("MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n"
"with fdisk or another tool.\n");
@@ -1352,21 +1393,26 @@ WhichToUse GPTData::UseWhichPartitions(void) {
mbrState = protectiveMBR.GetValidity();
if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) {
printf("\n\a***************************************************************\n"
"Found invalid GPT and valid MBR; converting MBR to GPT format.\n"
"THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n"
"you don't want to convert your MBR partitions to GPT format!\n"
"***************************************************************\n\n");
printf("\n***************************************************************\n"
"Found invalid GPT and valid MBR; converting MBR to GPT format.\n");
if (!justLooking) {
printf("\aTHIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n"
"you don't want to convert your MBR partitions to GPT format!\n");
} // if
printf("***************************************************************\n\n");
which = use_mbr;
} // if
if ((state == gpt_invalid) && bsdFound) {
printf("\n\a**********************************************************************\n"
printf("\n**********************************************************************\n"
"Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n"
"to GPT format. THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n"
"to GPT format.");
if (!justLooking) {
printf("\a THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n"
"BSD partition will likely be unusable. Exit by typing 'q' if you don't\n"
"want to convert your BSD partitions to GPT format!\n"
"**********************************************************************\n\n");
"want to convert your BSD partitions to GPT format!");
} // if
printf("\n**********************************************************************\n\n");
which = use_bsd;
} // if
@@ -1539,6 +1585,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
int allOK = 1, typeCode, bootable;
uint64_t length;
char line[255];
char* junk;
if ((mbrPart < 0) || (mbrPart > 3)) {
printf("MBR partition %d is out of range; omitting it.\n", mbrPart + 1);
@@ -1561,7 +1608,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
do {
printf("Enter an MBR hex code (default %02X): ",
typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256);
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
sscanf(line, "%x", &typeCode);
if (line[0] == '\n')
typeCode = partitions[gptPart].GetHexType() / 256;
@@ -1586,6 +1633,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
// the GPT data, and then exit.
int GPTData::XFormToMBR(void) {
char line[255];
char* junk;
int i, j, numParts, numConverted = 0;
uint32_t partNums[4];
@@ -1601,7 +1649,7 @@ int GPTData::XFormToMBR(void) {
if (numParts > 4) { // Over four partitions; engage in triage
printf("Type from one to four GPT partition numbers, separated by spaces, to be\n"
"used in the MBR, in sequence: ");
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
numParts = sscanf(line, "%d %d %d %d", &partNums[0], &partNums[1],
&partNums[2], &partNums[3]);
} else { // Four or fewer partitions; convert them all
@@ -1626,6 +1674,7 @@ int GPTData::XFormToMBR(void) {
void GPTData::MakeHybrid(void) {
uint32_t partNums[3];
char line[255];
char* junk;
int numParts, numConverted = 0, i, j, typeCode, mbrNum;
char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe)
char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
@@ -1638,7 +1687,7 @@ void GPTData::MakeHybrid(void) {
// hybrid MBR....
printf("Type from one to three GPT partition numbers, separated by spaces, to be\n"
"added to the hybrid MBR, in sequence: ");
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
numParts = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]);
if (numParts > 0) {
@@ -1690,7 +1739,7 @@ void GPTData::MakeHybrid(void) {
printf("Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): ");
// Comment on above: Mac OS treats disks with more than one
// 0xEE MBR partition as MBR disks, not as GPT disks.
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
sscanf(line, "%x", &typeCode);
if (line[0] == '\n')
typeCode = 0;
@@ -1951,8 +2000,8 @@ 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",
original, *sector);
"alignment purposes. Use 'l' on the experts' menu to adjust alignment.\n",
(unsigned long long) original, (unsigned long long) *sector);
} 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"

2
gpt.h
View File

@@ -61,6 +61,7 @@ protected:
uint32_t blockSize; // device block size
uint64_t diskSize; // size of device, in blocks
GPTValidity state; // is GPT valid?
int justLooking; // Set to 1 if program launched with "-l" or if read-only
int mainCrcOk;
int secondCrcOk;
int mainPartsCrcOk;
@@ -135,6 +136,7 @@ public:
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);

View File

@@ -187,6 +187,7 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
// Change the type code on the partition.
void GPTPart::ChangeType(void) {
char typeName[255], line[255];
char* junk;
int typeNum = 0xFFFF;
// uint16_t typeNum = 0xFFFF;
GUIDData newType;
@@ -195,7 +196,7 @@ void GPTPart::ChangeType(void) {
// printf("Current type is '%s'\n", typeHelper.GUIDToName(partitionType, typeName));
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
printf("Hex code (L to show codes, 0 to enter raw code): ");
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
sscanf(line, "%X", &typeNum);
if ((line[0] == 'L') || (line[0] == 'l'))
typeHelper.ShowTypes();
@@ -215,6 +216,7 @@ void GPTPart::ChangeType(void) {
// string. This function creates a simple-minded copy for this.
void GPTPart::SetName(unsigned char* theName) {
char newName[NAME_SIZE]; // New name
char* junk;
int i;
// Blank out new name string, just to be on the safe side....
@@ -223,7 +225,7 @@ void GPTPart::SetName(unsigned char* theName) {
if (theName == NULL) { // No name specified, so get one from the user
printf("Enter name: ");
fgets(newName, NAME_SIZE / 2, stdin);
junk = fgets(newName, NAME_SIZE / 2, stdin);
// Input is likely to include a newline, so remove it....
i = strlen(newName);

4
mbr.cc
View File

@@ -289,7 +289,9 @@ void MBRData::WriteMBRData(int fd) {
// Now write that data structure...
lseek64(fd, 0, SEEK_SET);
write(fd, &tempMBR, 512);
if (write(fd, &tempMBR, 512) != 512) {
fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
} // if
// Reverse the byte order back, if necessary
if (IsLittleEndian() == 0) {

View File

@@ -20,6 +20,13 @@
#include <sys/types.h>
// As of 1/2010, BLKPBSZGET is very new, so I'm explicitly defining it if
// it's not already defined. This should become unnecessary in the future.
// Note that this is a Linux-only ioctl....
#ifndef BLKPBSZGET
#define BLKPBSZGET _IO(0x12,123)
#endif
using namespace std;
// Get a numeric value from the user, between low and high (inclusive).
@@ -30,12 +37,13 @@ using namespace std;
int GetNumber(int low, int high, int def, const char prompt[]) {
int response, num;
char line[255];
char* junk;
if (low != high) { // bother only if low and high differ...
response = low - 1; // force one loop by setting response outside range
while ((response < low) || (response > high)) {
printf("%s", prompt);
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
num = sscanf(line, "%d", &response);
if (num == 1) { // user provided a response
if ((response < low) || (response > high))
@@ -55,10 +63,11 @@ int GetNumber(int low, int high, int def, const char prompt[]) {
char GetYN(void) {
char line[255];
char response = '\0';
char* junk;
while ((response != 'Y') && (response != 'N')) {
printf("(Y/N): ");
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &response);
if (response == 'y') response = 'Y';
if (response == 'n') response = 'N';
@@ -80,11 +89,12 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[])
uint64_t mult = 1;
char suffix;
char line[255];
char* junk;
response = low - 1; // Ensure one pass by setting a too-low initial value
while ((response < low) || (response > high)) {
printf("%s", prompt);
fgets(line, 255, stdin);
junk = fgets(line, 255, stdin);
// Remove leading spaces, if present
while (line[0] == ' ')
@@ -189,16 +199,16 @@ char* BytesToSI(uint64_t size, char theValue[]) {
// returns an error condition, print a warning but return a value of SECTOR_SIZE
// (512)..
int GetBlockSize(int fd) {
int err, result;
int err = -1, result;
#ifdef __APPLE__
err = ioctl(fd, DKIOCGETBLOCKSIZE, &result);
#else
#endif
#ifdef __FreeBSD__
err = ioctl(fd, DIOCGSECTORSIZE, &result);
#else
err = ioctl(fd, BLKSSZGET, &result);
#endif
#ifdef __linux__
err = ioctl(fd, BLKSSZGET, &result);
#endif
if (err == -1) {
@@ -221,51 +231,78 @@ int GetBlockSize(int fd) {
return (result);
} // GetBlockSize()
// 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;
#if defined (__linux__) && defined (BLKPBSZGET)
err = ioctl(fd, BLKPBSZGET, &physicalSectorSize);
// printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize);
#else
err = -1;
#endif
if (err < 0) {
result = 8;
} else {
result = physicalSectorSize / GetBlockSize(fd);
} // if/else
return result;
} // FindAlignment(int)
// The same as FindAlignment(int), but opens and closes a device by filename
int FindAlignment(char deviceFilename[]) {
int fd;
int retval = 1;
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
retval = FindAlignment(fd);
close(fd);
} // if
return retval;
} // FindAlignment(char)
// Return a plain-text name for a partition type.
// Convert a GUID to a string representation, suitable for display
// to humans....
char* GUIDToStr(struct GUIDData theGUID, char* theString) {
uint64_t block;
unsigned long long blocks[11], block;
if (theString != NULL) {
block = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF));
sprintf(theString, "%08llX-", (unsigned long long) block);
block = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32;
sprintf(theString, "%s%04llX-", theString, (unsigned long long) block);
block = (theGUID.data1 & UINT64_C(0xFFFF000000000000)) >> 48;
sprintf(theString, "%s%04llX-", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0x00000000000000FF));
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0x000000000000FF00)) >> 8;
sprintf(theString, "%s%02llX-", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0x0000000000FF0000)) >> 16;
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0x00000000FF000000)) >> 24;
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0x000000FF00000000)) >> 32;
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0x0000FF0000000000)) >> 40;
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0x00FF000000000000)) >> 48;
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
block = (theGUID.data2 & UINT64_C(0xFF00000000000000)) >> 56;
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
} // if
if (theString != NULL) {
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]);
} // if
return theString;
} // GUIDToStr()
// Get a GUID from the user
GUIDData GetGUID(void) {
uint64_t part1, part2, part3, part4, part5;
unsigned long long part1, part2, part3, part4, part5;
int entered = 0;
char temp[255], temp2[255];
char* junk;
GUIDData theGUID;
printf("\nA GUID is entered in five segments of from two to six bytes, with\n"
"dashes between segments.\n");
printf("Enter the entire GUID, a four-byte hexadecimal number for the first segment, or\n"
"'R' to generate the entire GUID randomly: ");
fgets(temp, 255, stdin);
junk = fgets(temp, 255, stdin);
// If user entered 'r' or 'R', generate GUID randomly....
if ((temp[0] == 'r') || (temp[0] == 'R')) {
@@ -308,17 +345,17 @@ GUIDData GetGUID(void) {
if (entered == 0) {
sscanf(temp, "%llx", &part1);
printf("Enter a two-byte hexadecimal number for the second segment: ");
fgets(temp, 255, stdin);
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part2);
printf("Enter a two-byte hexadecimal number for the third segment: ");
fgets(temp, 255, stdin);
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part3);
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
printf("Enter a two-byte hexadecimal number for the fourth segment: ");
fgets(temp, 255, stdin);
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part4);
printf("Enter a six-byte hexadecimal number for the fifth segment: ");
fgets(temp, 255, stdin);
junk = fgets(temp, 255, stdin);
sscanf(temp, "%llx", &part5);
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
((part4 & UINT64_C(0x00000000000000FF)) << 8) +

View File

@@ -60,6 +60,8 @@ char GetYN(void);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[]);
char* BytesToSI(uint64_t size, char theValue[]);
int GetBlockSize(int fd);
int FindAlignment(int fd);
int FindAlignment(char device[]);
char* GUIDToStr(struct GUIDData theGUID, char* theString);
GUIDData GetGUID(void);
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian