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.
diff --git a/gpt.cc b/gpt.cc
index c34c862..7204f2c 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -40,6 +40,7 @@
partitions = NULL;
state = gpt_valid;
strcpy(device, "");
+ justLooking = 0;
mainCrcOk = 0;
secondCrcOk = 0;
mainPartsCrcOk = 0;
@@ -58,6 +59,7 @@
partitions = NULL;
state = gpt_invalid;
strcpy(device, "");
+ justLooking = 0;
mainCrcOk = 0;
secondCrcOk = 0;
mainPartsCrcOk = 0;
@@ -296,7 +298,7 @@
} 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 @@
} 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 @@
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 @@
// 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 @@
// 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 @@
} // 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 @@
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 @@
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 @@
// 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 @@
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 @@
} // 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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
(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 @@
} 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 @@
// 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 @@
// 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 @@
#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 @@
// 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 @@
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 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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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"