A few minor bug fixes; backup function now accepts dd output of MBR,
main header, and main partition table, as well as gdisk-generated
backups.
diff --git a/CHANGELOG b/CHANGELOG
index 7139adb..70098ce 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,22 @@
+0.6.4 (??/??/2010):
+-------------------
+
+- Fixed bug in the -E option to sgdisk; it was actually returning the
+ last free sector, not the last free sector in the largest free block.
+
+- Fixed bug in -t option to sgdisk; it was corrupting partition type
+ codes.
+
+- Fixed minor alignment bug in partition summary list ('p' from any menu)
+ when partition sizes are between 1000 and 1024 units.
+
+- Backup restore function ('l' on recovery & transformation menu) now
+ accepts both backups generated by GPT fdisk and backups created by a
+ direct copy (via dd, etc.) of the MBR, main GPT header, and main GPT
+ partition table, in that order. ("dd if=/dev/sda of=backup.gpt bs=512
+ count=34" will do this on Linux for a disk with a typical-sized GPT table
+ of 128 entries.)
+
0.6.3 (2/3/2010):
------------------
diff --git a/bsd.cc b/bsd.cc
index f1d1ade..5077555 100644
--- a/bsd.cc
+++ b/bsd.cc
@@ -37,7 +37,7 @@
} // default constructor
BSDData::~BSDData(void) {
- free(partitions);
+ delete[] partitions;
} // destructor
// Read BSD disklabel data from the specified device filename. This function
@@ -132,7 +132,7 @@
// If the state is good, go ahead and load the main partition data....
if (state == bsd) {
- partitions = (struct BSDRecord*) malloc(numParts * sizeof (struct BSDRecord));
+ partitions = new struct BSDRecord[numParts * sizeof(struct BSDRecord)];
for (i = 0; i < numParts; i++) {
// Once again, we use the buffer, but index it using a BSDRecord
// pointer (dangerous, but effective)....
diff --git a/diskio-unix.cc b/diskio-unix.cc
index 8fbc7b5..00ffd99 100644
--- a/diskio-unix.cc
+++ b/diskio-unix.cc
@@ -184,6 +184,7 @@
} // DiskIO::DiskSync()
// Seek to the specified sector. Returns 1 on success, 0 on failure.
+// Note that seeking beyond the end of the file is NOT detected as a failure!
int DiskIO::Seek(uint64_t sector) {
int retval = 1;
off_t seekTo, sought;
@@ -208,7 +209,7 @@
// size with the number of bytes read.
// Returns the number of bytes read into buffer.
int DiskIO::Read(void* buffer, int numBytes) {
- int blockSize = 512, numBlocks, retval = 0;
+ int blockSize, numBlocks, retval = 0;
char* tempSpace;
// If disk isn't open, try to open it....
@@ -221,11 +222,12 @@
blockSize = GetBlockSize();
if (numBytes <= blockSize) {
numBlocks = 1;
- tempSpace = (char*) malloc(blockSize);
+ tempSpace = new char [blockSize];
} else {
numBlocks = numBytes / blockSize;
- if ((numBytes % blockSize) != 0) numBlocks++;
- tempSpace = (char*) malloc(numBlocks * blockSize);
+ if ((numBytes % blockSize) != 0)
+ numBlocks++;
+ tempSpace = new char [numBlocks * blockSize];
} // if/else
// Read the data into temporary space, then copy it to buffer
@@ -236,7 +238,7 @@
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
retval = numBytes;
- free(tempSpace);
+ delete[] tempSpace;
} // if (isOpen)
return retval;
} // DiskIO::Read()
@@ -259,17 +261,14 @@
blockSize = GetBlockSize();
if (numBytes <= blockSize) {
numBlocks = 1;
- tempSpace = (char*) malloc(blockSize);
+ tempSpace = new char [blockSize];
} else {
numBlocks = numBytes / blockSize;
if ((numBytes % blockSize) != 0) numBlocks++;
- tempSpace = (char*) malloc(numBlocks * blockSize);
+ tempSpace = new char [numBlocks * blockSize];
} // if/else
// Copy the data to my own buffer, then write it
-/* for (i = 0; i < numBytes; i++) {
- tempSpace[i] = ((char*) buffer)[i];
- } // for */
memcpy(tempSpace, buffer, numBytes);
for (i = numBytes; i < numBlocks * blockSize; i++) {
tempSpace[i] = 0;
@@ -280,7 +279,7 @@
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
retval = numBytes;
- free(tempSpace);
+ delete[] tempSpace;
} // if (isOpen)
return retval;
} // DiskIO:Write()
diff --git a/diskio-windows.cc b/diskio-windows.cc
index e3547c6..d5cd84b 100644
--- a/diskio-windows.cc
+++ b/diskio-windows.cc
@@ -19,7 +19,7 @@
#include <winioctl.h>
#define fstat64 fstat
#define stat64 stat
-#define S_IRGRP 0
+//#define S_IRGRP 0
#define S_IROTH 0
#include <stdio.h>
#include <string>
@@ -64,7 +64,9 @@
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd == INVALID_HANDLE_VALUE) {
CloseHandle(fd);
- cerr << "Problem opening " << realFilename << " for reading!\n";
+ cerr << "Problem opening ";
+ cerr << realFilename;
+ cerr << " for reading!\n";
realFilename = "";
userFilename = "";
isOpen = 0;
@@ -220,11 +222,12 @@
blockSize = GetBlockSize();
if (numBytes <= blockSize) {
numBlocks = 1;
- tempSpace = (char*) malloc(blockSize);
+ tempSpace = new char [blockSize];
} else {
numBlocks = numBytes / blockSize;
- if ((numBytes % blockSize) != 0) numBlocks++;
- tempSpace = (char*) malloc(numBlocks * blockSize);
+ if ((numBytes % blockSize) != 0)
+ numBlocks++;
+ tempSpace = new char [numBlocks * blockSize];
} // if/else
// Read the data into temporary space, then copy it to buffer
@@ -237,7 +240,7 @@
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
retval = numBytes;
- free(tempSpace);
+ delete[] tempSpace;
} // if (isOpen)
return retval;
} // DiskIO::Read()
@@ -261,11 +264,11 @@
blockSize = GetBlockSize();
if (numBytes <= blockSize) {
numBlocks = 1;
- tempSpace = (char*) malloc(blockSize);
+ tempSpace = new char [blockSize];
} else {
numBlocks = numBytes / blockSize;
if ((numBytes % blockSize) != 0) numBlocks++;
- tempSpace = (char*) malloc(numBlocks * blockSize);
+ tempSpace = new char [numBlocks * blockSize];
} // if/else
// Copy the data to my own buffer, then write it
@@ -282,7 +285,7 @@
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
retval = numBytes;
- free(tempSpace);
+ delete[] tempSpace;
} // if (isOpen)
return retval;
} // DiskIO:Write()
diff --git a/diskio.cc b/diskio.cc
index 17a44a4..1bb0178 100644
--- a/diskio.cc
+++ b/diskio.cc
@@ -43,12 +43,10 @@
realFilename = "";
isOpen = 0;
openForWrite = 0;
- sectorData = NULL;
} // constructor
DiskIO::~DiskIO(void) {
Close();
- free(sectorData);
} // destructor
// Open a disk device for reading. Returns 1 on success, 0 on failure.
diff --git a/diskio.h b/diskio.h
index b27e977..630d1b4 100644
--- a/diskio.h
+++ b/diskio.h
@@ -51,7 +51,6 @@
string realFilename;
int isOpen;
int openForWrite;
- uint8_t *sectorData;
#ifdef _WIN32
HANDLE fd;
#else
@@ -76,6 +75,7 @@
int FindAlignment(const string & filename);
int IsOpen(void) {return isOpen;}
int IsOpenForWrite(void) {return openForWrite;}
+ string GetName(void) {return realFilename;}
uint64_t DiskSize(int* err);
}; // struct GPTPart
diff --git a/gdisk.cc b/gdisk.cc
index 5a2c905..b81a802 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -29,7 +29,6 @@
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";
diff --git a/gpt.cc b/gpt.cc
index 562a085..a2e216f 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -82,7 +82,7 @@
// Destructor
GPTData::~GPTData(void) {
- free(partitions);
+ delete[] partitions;
} // GPTData destructor
/*********************************************************************
@@ -342,8 +342,8 @@
} // GPTData::CheckHeaderValidity()
// Check the header CRC to see if it's OK...
-// Note: Must be called BEFORE byte-order reversal on big-endian
-// systems!
+// Note: Must be called with header in LITTLE-ENDIAN
+// (x86, x86-64, etc.) byte order.
int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
uint32_t oldCRC, newCRC, hSize;
@@ -648,53 +648,22 @@
// Loads the GPT, as much as possible. Returns 1 if this seems to have
// succeeded, 0 if there are obvious problems....
int GPTData::ForceLoadGPTData(void) {
- int allOK = 1, validHeaders;
- uint64_t seekTo;
- uint8_t* storage;
- uint32_t newCRC, sizeOfParts;
+ int allOK, validHeaders, loadedTable = 1;
- // Seek to and read the main GPT header
- if (myDisk.Seek(1)) {
- if (myDisk.Read(&mainHeader, 512) != 512) { // read main GPT header
- cerr << "Warning! Error " << errno << " reading main GPT header!\n";
- } // if read not OK
- } else allOK = 0; // if/else seek OK
- mainCrcOk = CheckHeaderCRC(&mainHeader);
- if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
- ReverseHeaderBytes(&mainHeader);
+ allOK = LoadHeader(&mainHeader, myDisk, 1, &mainCrcOk);
- // Load backup header, check its CRC, and store the results of the
- // check for future reference. Load backup header using pointer in main
- // header if possible; but if main header has a CRC error, or if it
- // points to beyond the end of the disk, load the last sector of the
- // disk instead.
- if (mainCrcOk) {
- if (mainHeader.backupLBA < diskSize) {
- seekTo = mainHeader.backupLBA;
- } else {
- seekTo = diskSize - UINT64_C(1);
+ if (mainCrcOk && (mainHeader.backupLBA < diskSize)) {
+ allOK = LoadHeader(&secondHeader, myDisk, mainHeader.backupLBA, &secondCrcOk) && allOK;
+ } else {
+ if (mainHeader.backupLBA >= diskSize)
cout << "Warning! Disk size is smaller than the main header indicates! Loading\n"
<< "secondary header from the last sector of the disk! You should use 'v' to\n"
<< "verify disk integrity, and perhaps options on the experts' menu to repair\n"
<< "the disk.\n";
- } // else
- } else {
- seekTo = diskSize - UINT64_C(1);
- } // if/else (mainCrcOk)
-
- if (myDisk.Seek(seekTo)) {
- if (myDisk.Read(&secondHeader, 512) != 512) { // read secondary GPT header
- cerr << "Warning! Error " << errno << " reading secondary GPT header!\n";
- } // if
- secondCrcOk = CheckHeaderCRC(&secondHeader);
- if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
- ReverseHeaderBytes(&secondHeader);
- } else {
- allOK = 0;
+ allOK = LoadHeader(&secondHeader, myDisk, diskSize - UINT64_C(1), &secondCrcOk) && allOK;
+ } // if/else
+ if (!allOK)
state = gpt_invalid;
- cerr << "Unable to seek to secondary GPT header at sector "
- << (diskSize - (UINT64_C(1))) << "!\n";
- } // if/else lseek
// Return valid headers code: 0 = both headers bad; 1 = main header
// good, backup bad; 2 = backup header good, main header bad;
@@ -734,37 +703,32 @@
} else { // bad main header CRC and backup header CRC is OK
state = gpt_corrupt;
if (LoadSecondTableAsMain()) {
+ loadedTable = 2;
cerr << "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n";
} else { // backup table bad, bad main header CRC, but try main table in desperation....
if (LoadMainTable() == 0) {
allOK = 0;
+ loadedTable = 0;
cerr << "\a\aWarning! Unable to load either main or backup partition table!\n";
} // if
} // if/else (LoadSecondTableAsMain())
} // if/else (load partition table)
- // Load backup partition table into temporary storage to check
- // its CRC and store the results, then discard this temporary
- // storage, since we don't use it in any but recovery operations
- seekTo = secondHeader.partitionEntriesLBA;
- if ((myDisk.Seek(seekTo)) && (secondCrcOk)) {
- sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
- storage = (uint8_t*) malloc(sizeOfParts);
- if (myDisk.Read(storage, sizeOfParts) != (int) sizeOfParts) {
- cerr << "Warning! Error " << errno << " reading backup partition table!\n";
- } // if
- newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
- free(storage);
- secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
- } // if
+ if (loadedTable == 1)
+ secondPartsCrcOk = CheckTable(&secondHeader);
+ else if (loadedTable == 2)
+ mainPartsCrcOk = CheckTable(&mainHeader);
+ else
+ mainPartsCrcOk = secondPartsCrcOk = 0;
// Problem with main partition table; if backup is OK, use it instead....
if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) {
state = gpt_corrupt;
allOK = allOK && LoadSecondTableAsMain();
+ mainPartsCrcOk = 0; // LoadSecondTableAsMain() resets this, so re-flag as bad
cerr << "\aWarning! Main partition table CRC mismatch! Loaded backup "
<< "partition table\ninstead of main partition table!\n\n";
- } // if
+ } // if */
// Check for valid CRCs and warn if there are problems
if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) ||
@@ -783,28 +747,7 @@
// sensible!
// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
int GPTData::LoadMainTable(void) {
- int retval = 1;
- uint32_t newCRC, sizeOfParts;
-
- if (myDisk.OpenForRead(device)) {
- // Set internal data structures for number of partitions on the disk
- SetGPTSize(mainHeader.numParts);
-
- // Load main partition table, and record whether its CRC
- // matches the stored value
- if (!myDisk.Seek(mainHeader.partitionEntriesLBA))
- retval = 0;
- sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
- if (myDisk.Read(partitions, sizeOfParts) != (int) sizeOfParts) {
- cerr << "Warning! Error " << errno << " when loading the main partition table!\n";
- retval = 0;
- } // if
- newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
- mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
- if (IsLittleEndian() == 0)
- ReversePartitionBytes();
- } else retval = 0; // if open for read....
- return retval;
+ return LoadPartitionTable(mainHeader, myDisk);
} // GPTData::LoadMainTable()
// Load the second (backup) partition table as the primary partition
@@ -812,47 +755,103 @@
// partition table is damaged.
// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
int GPTData::LoadSecondTableAsMain(void) {
- uint64_t seekTo;
- uint32_t sizeOfParts, newCRC;
- int retval = 1;
+ return LoadPartitionTable(secondHeader, myDisk);
+} // GPTData::LoadSecondTableAsMain()
- if (myDisk.OpenForRead(device)) {
- seekTo = secondHeader.partitionEntriesLBA;
- retval = myDisk.Seek(seekTo);
+// Load a single GPT header (main or backup) from the specified disk device and
+// sector. Applies byte-order corrections on big-endian platforms. Sets crcOk
+// value appropriately.
+// Returns 1 on success, 0 on failure. Note that CRC errors do NOT qualify as
+// failure.
+int GPTData::LoadHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector, int *crcOk) {
+ int allOK = 1;
+
+ disk.Seek(sector);
+ if (disk.Read(header, 512) != 512) {
+ cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n";
+ allOK = 0;
+ } // if
+ *crcOk = CheckHeaderCRC(header);
+
+ // Reverse byte order, if necessary
+ if (IsLittleEndian() == 0) {
+ ReverseHeaderBytes(header);
+ } // if
+ return allOK;
+} // GPTData::LoadHeader
+
+// Load a partition table (either main or secondary) from the specified disk,
+// using header as a reference for what to load. If sector != 0 (the default
+// is 0), loads from the specified sector; otherwise loads from the sector
+// indicated in header.
+// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
+int GPTData::LoadPartitionTable(const struct GPTHeader & header, DiskIO & disk, uint64_t sector) {
+ uint32_t sizeOfParts, newCRC;
+ int retval;
+
+ if (disk.OpenForRead()) {
+ if (sector == 0) {
+ retval = disk.Seek(header.partitionEntriesLBA);
+ } else {
+ retval = disk.Seek(sector);
+ } // if/else
if (retval == 1) {
- SetGPTSize(secondHeader.numParts);
- sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
- if (myDisk.Read(partitions, sizeOfParts) != (int) sizeOfParts) {
+ SetGPTSize(header.numParts);
+ sizeOfParts = header.numParts * header.sizeOfPartitionEntries;
+ if (disk.Read(partitions, sizeOfParts) != (int) sizeOfParts) {
cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n";
retval = 0;
} // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
- secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
- mainPartsCrcOk = secondPartsCrcOk;
+ mainPartsCrcOk = secondPartsCrcOk = (newCRC == header.partitionEntriesCRC);
if (IsLittleEndian() == 0)
ReversePartitionBytes();
- if (!secondPartsCrcOk) {
- cout << "Caution! After loading backup partitions, the CRC still doesn't check out!\n";
+ if (!mainPartsCrcOk) {
+ cout << "Caution! After loading partitions, the CRC doesn't check out!\n";
} // if
} else {
- cerr << "Error! Couldn't seek to backup partition table!\n";
+ cerr << "Error! Couldn't seek to partition table!\n";
} // if/else
} else {
cerr << "Error! Couldn't open device " << device
- << " when recovering backup partition table!\n";
+ << " when reading partition table!\n";
retval = 0;
} // if/else
return retval;
-} // GPTData::LoadSecondTableAsMain()
+} // GPTData::LoadPartitionsTable()
+
+// Check the partition table pointed to by header, but don't keep it
+// around.
+// Returns 1 if the CRC is OK, 0 if not or if there was a read error.
+int GPTData::CheckTable(struct GPTHeader *header) {
+ uint32_t sizeOfParts, newCRC;
+ uint8_t *storage;
+ int newCrcOk = 0;
+
+ // Load backup partition table into temporary storage to check
+ // its CRC and store the results, then discard this temporary
+ // storage, since we don't use it in any but recovery operations
+ if (myDisk.Seek(header->partitionEntriesLBA)) {
+ sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
+ storage = new uint8_t[sizeOfParts];
+ if (myDisk.Read(storage, sizeOfParts) != (int) sizeOfParts) {
+ cerr << "Warning! Error " << errno << " reading backup partition table!\n";
+ } else {
+ newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
+ newCrcOk = (newCRC == header->partitionEntriesCRC);
+ } // if/else
+ delete[] storage;
+ } // if
+ return newCrcOk;
+} // GPTData::CheckTable()
// 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, littleEndian;
char answer;
- uint64_t secondTable;
+// uint64_t secondTable;
uint32_t numParts;
- uint64_t offset;
littleEndian = IsLittleEndian();
@@ -907,18 +906,8 @@
// Pull out some data that's needed before doing byte-order reversal on
// big-endian systems....
numParts = mainHeader.numParts;
- secondTable = secondHeader.partitionEntriesLBA;
-/* if (IsLittleEndian() == 0) {
- // Reverse partition bytes first, since that function requires non-reversed
- // data from the main header....
- ReversePartitionBytes();
- ReverseHeaderBytes(&mainHeader);
- ReverseHeaderBytes(&secondHeader);
- } // if */
+
RecomputeCRCs();
-/* ReverseHeaderBytes(&mainHeader);
- ReverseHeaderBytes(&secondHeader);
- ReversePartitionBytes(); */
if ((allOK) && (!quiet)) {
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"
@@ -938,59 +927,22 @@
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()...)
+ allOK = SaveHeader(&mainHeader, myDisk, 1);
// 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()...)
+ allOK = SavePartitionTable(myDisk, mainHeader.partitionEntriesLBA);
} // if (allOK)
// Now seek to near the end to write the secondary GPT....
- if (allOK) {
- offset = (uint64_t) secondTable;
- if (myDisk.Seek(offset) != 1) {
- allOK = 0;
- cerr << "Unable to seek to end of disk! Perhaps the 'e' option on the experts' menu\n"
- << "will resolve this problem.\n";
- } // if
- } // if
-
- // Now write the secondary partition tables....
- if (allOK) {
- if (!littleEndian)
- ReversePartitionBytes();
- if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
- allOK = 0;
- if (!littleEndian)
- ReversePartitionBytes();
- } // if (allOK)
+ allOK = SavePartitionTable(myDisk, secondHeader.partitionEntriesLBA);
+ if (!allOK)
+ cerr << "Unable to save backup partition table! Perhaps the 'e' option on the experts'\n"
+ << "menu will resolve this problem.\n";
// Now write the secondary GPT header...
if (allOK) {
- offset = mainHeader.backupLBA;
- if (!littleEndian)
- ReverseHeaderBytes(&secondHeader);
- if (myDisk.Seek(offset)) {
- if (myDisk.Write(&secondHeader, 512) == -1)
- allOK = 0;
- } else allOK = 0; // if (myDisk.Seek()...)
- if (!littleEndian)
- ReverseHeaderBytes(&secondHeader);
+ allOK = SaveHeader(&secondHeader, myDisk, mainHeader.backupLBA);
} // if (allOK)
// re-read the partition table
@@ -1015,14 +967,6 @@
cout << "Aborting write of new partition table.\n";
} // if
-/* if (IsLittleEndian() == 0) {
- // Reverse (normalize) header bytes first, since ReversePartitionBytes()
- // requires non-reversed data in mainHeader...
- ReverseHeaderBytes(&mainHeader);
- ReverseHeaderBytes(&secondHeader);
- ReversePartitionBytes();
- } // if */
-
return (allOK);
} // GPTData::SaveGPTData()
@@ -1034,7 +978,6 @@
// identical to the main partition table on healthy disks.
int GPTData::SaveGPTBackup(const string & filename) {
int allOK = 1;
- uint32_t numParts;
DiskIO backupFile;
if (backupFile.OpenForWrite(filename)) {
@@ -1044,35 +987,19 @@
// backup. I'm favoring misses over false alarms....
RecomputeCRCs();
- // Reverse the byte order, if necessary....
- numParts = mainHeader.numParts;
- if (IsLittleEndian() == 0) {
- ReversePartitionBytes();
- ReverseHeaderBytes(&mainHeader);
- ReverseHeaderBytes(&secondHeader);
- } // if
-
- // Now write the protective MBR...
protectiveMBR.WriteMBRData(&backupFile);
- // Now write the main GPT header...
- if (allOK)
+ if (allOK) {
// MBR write closed disk, so re-open and seek to end....
backupFile.OpenForWrite();
- backupFile.Seek(1);
- if (backupFile.Write(&mainHeader, 512) == -1)
- allOK = 0;
+ allOK = SaveHeader(&mainHeader, backupFile, 1);
+ } // if (allOK)
- // Now write the secondary GPT header...
if (allOK)
- if (backupFile.Write(&secondHeader, 512) == -1)
- allOK = 0;
+ allOK = SaveHeader(&secondHeader, backupFile, 2);
- // Now write the main partition tables...
- if (allOK) {
- if (backupFile.Write(partitions, GPT_SIZE * numParts) == -1)
- allOK = 0;
- } // if
+ if (allOK)
+ allOK = SavePartitionTable(backupFile, 3);
if (allOK) { // writes completed OK
cout << "The operation has completed successfully.\n";
@@ -1081,13 +1008,6 @@
<< "It may not be usable!\n";
} // if/else
backupFile.Close();
-
- // Now reverse the byte-order reversal, if necessary....
- if (IsLittleEndian() == 0) {
- ReverseHeaderBytes(&mainHeader);
- ReverseHeaderBytes(&secondHeader);
- ReversePartitionBytes();
- } // if
} else {
cerr << "Unable to open file " << filename << " for writing! Aborting!\n";
allOK = 0;
@@ -1095,14 +1015,54 @@
return allOK;
} // GPTData::SaveGPTBackup()
+// Write a GPT header (main or backup) to the specified sector. Used by both
+// the SaveGPTData() and SaveGPTBackup() functions.
+// Should be passed an architecture-appropriate header (DO NOT call
+// ReverseHeaderBytes() on the header before calling this function)
+// Returns 1 on success, 0 on failure
+int GPTData::SaveHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector) {
+ int littleEndian, allOK = 1;
+
+ littleEndian = IsLittleEndian();
+ if (!littleEndian)
+ ReverseHeaderBytes(header);
+ if (disk.Seek(sector)) {
+ if (disk.Write(header, 512) == -1)
+ allOK = 0;
+ } else allOK = 0; // if (disk.Seek()...)
+ if (!littleEndian)
+ ReverseHeaderBytes(header);
+ return allOK;
+} // GPTData::SaveHeader()
+
+// Save the partitions to the specified sector. Used by both the SaveGPTData()
+// and SaveGPTBackup() functions.
+// Should be passed an architecture-appropriate header (DO NOT call
+// ReverseHeaderBytes() on the header before calling this function)
+// Returns 1 on success, 0 on failure
+int GPTData::SavePartitionTable(DiskIO & disk, uint64_t sector) {
+ int littleEndian, allOK = 1;
+
+ littleEndian = IsLittleEndian();
+ if (disk.Seek(sector)) {
+ if (!littleEndian)
+ ReversePartitionBytes();
+ if (disk.Write(partitions, mainHeader.sizeOfPartitionEntries * mainHeader.numParts) == -1)
+ allOK = 0;
+ if (!littleEndian)
+ ReversePartitionBytes();
+ } else allOK = 0; // if (myDisk.Seek()...)
+ return allOK;
+} // GPTData::SavePartitionTable()
+
// Load GPT data from a backup file created by SaveGPTBackup(). This function
// does minimal error checking. It returns 1 if it completed successfully,
// 0 if there was a problem. In the latter case, it creates a new empty
// set of partitions.
int GPTData::LoadGPTBackup(const string & filename) {
- int allOK = 1, val;
- uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC;
- int littleEndian = 1;
+ int allOK = 1, val, err;
+ uint32_t numParts, sizeOfEntries;
+ int littleEndian = 1, shortBackup = 0;
DiskIO backupFile;
if (backupFile.OpenForRead(filename)) {
@@ -1112,29 +1072,20 @@
// Let the MBRData class load the saved MBR...
protectiveMBR.ReadMBRData(&backupFile, 0); // 0 = don't check block size
- // Load the main GPT header, check its vaility, and set the GPT
- // size based on the data
- if (backupFile.Read(&mainHeader, 512) != 512) {
- cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n";
- } // if
- mainCrcOk = CheckHeaderCRC(&mainHeader);
+ LoadHeader(&mainHeader, backupFile, 1, &mainCrcOk);
- // Reverse byte order, if necessary
- if (littleEndian == 0) {
- ReverseHeaderBytes(&mainHeader);
- } // if
-
- // Load the backup GPT header in much the same way as the main
- // GPT header....
- if (backupFile.Read(&secondHeader, 512) != 512) {
- cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n";
- } // if
- secondCrcOk = CheckHeaderCRC(&secondHeader);
-
- // Reverse byte order, if necessary
- if (littleEndian == 0) {
- ReverseHeaderBytes(&secondHeader);
- } // if
+ // Check backup file size and rebuild second header if file is right
+ // size to be direct dd copy of MBR, main header, and main partition
+ // table; if other size, treat it like a GPT fdisk-generated backup
+ // file
+ shortBackup = ((backupFile.DiskSize(&err) * backupFile.GetBlockSize()) ==
+ (mainHeader.numParts * mainHeader.sizeOfPartitionEntries) + 1024);
+ if (shortBackup) {
+ RebuildSecondHeader();
+ secondCrcOk = mainCrcOk;
+ } else {
+ LoadHeader(&secondHeader, backupFile, 2, &secondCrcOk);
+ } // if/else
// Return valid headers code: 0 = both headers bad; 1 = main header
// good, backup bad; 2 = backup header good, main header bad;
@@ -1152,27 +1103,15 @@
SetGPTSize(numParts);
- // If current disk size doesn't match that of backup....
if (secondHeader.currentLBA != diskSize - UINT64_C(1)) {
cout << "Warning! Current disk size doesn't match that of the backup!\n"
<< "Adjusting sizes to match, but subsequent problems are possible!\n";
MoveSecondHeaderToEnd();
} // if
- // Load main partition table, and record whether its CRC
- // matches the stored value
- sizeOfParts = numParts * sizeOfEntries;
- if (backupFile.Read(partitions, sizeOfParts) != (int) sizeOfParts) {
- cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n";
- } // if
-
- newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
- mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
- secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
- // Reverse byte order, if necessary
- if (littleEndian == 0) {
- ReversePartitionBytes();
- } // if
+ if (!LoadPartitionTable(mainHeader, backupFile, (uint64_t) (3 - shortBackup)))
+ cerr << "Warning! Read error " << errno
+ << " loading partition table; strange behavior now likely!\n";
} else {
allOK = 0;
@@ -1318,7 +1257,7 @@
if (((firstBlock = FindFirstAvailable()) != 0) &&
(firstFreePart < mainHeader.numParts)) {
- lastBlock = FindLastAvailable(firstBlock);
+ lastBlock = FindLastAvailable();
firstInLargest = FindFirstInLargest();
// Get partition number....
@@ -1430,7 +1369,7 @@
} // if
myDisk.Seek(mainHeader.partitionEntriesLBA); // seek to partition table
tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
- emptyTable = (uint8_t*) malloc(tableSize);
+ emptyTable = new uint8_t[tableSize];
for (i = 0; i < tableSize; i++)
emptyTable[i] = 0;
sum = myDisk.Write(emptyTable, tableSize);
@@ -1466,6 +1405,7 @@
myDisk.Close();
cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n"
<< "other utilities. Program will now terminate.\n";
+ delete[] emptyTable;
} else {
cerr << "Problem opening " << device << " for writing! Program will now terminate.\n";
} // if/else (fd != -1)
@@ -1894,7 +1834,7 @@
// data.
if ((numEntries != mainHeader.numParts) || (numEntries != secondHeader.numParts)
|| (partitions == NULL)) {
- newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart));
+ newParts = new GPTPart [numEntries * sizeof (GPTPart)];
if (newParts != NULL) {
if (partitions != NULL) { // existing partitions; copy them over
GetPartRange(&i, &high);
@@ -1914,7 +1854,7 @@
} // for
trash = partitions;
partitions = newParts;
- free(trash);
+ delete[] trash;
} // if
} else { // No existing partition table; just create it
partitions = newParts;
@@ -2033,7 +1973,7 @@
// Set up the partition table....
if (partitions != NULL)
- free(partitions);
+ delete[] partitions;
partitions = NULL;
SetGPTSize(NUM_GPT_ENTRIES);
@@ -2297,10 +2237,9 @@
return selectedSegment;
} // GPTData::FindFirstInLargest()
-// Find the last available block on the disk at or after the start
-// block. Returns 0 if there are no available partitions after
-// (or including) start.
-uint64_t GPTData::FindLastAvailable(uint64_t start) {
+// Find the last available block on the disk.
+// Returns 0 if there are no available partitions
+uint64_t GPTData::FindLastAvailable(void) {
uint64_t last;
uint32_t i;
int lastMoved = 0;
diff --git a/gpt.h b/gpt.h
index f122570..2478648 100644
--- a/gpt.h
+++ b/gpt.h
@@ -8,7 +8,6 @@
#include <sys/types.h>
#include "gptpart.h"
#include "support.h"
-#include "parttypes.h"
#include "mbr.h"
#include "bsd.h"
#include "gptpart.h"
@@ -16,7 +15,7 @@
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
-#define GPTFDISK_VERSION "0.6.3"
+#define GPTFDISK_VERSION "0.6.4-pre1"
using namespace std;
@@ -74,6 +73,12 @@
int sectorAlignment; // Start & end partitions at multiples of sectorAlignment
int beQuiet;
WhichToUse whichWasUsed;
+
+ int LoadHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector, int *crcOk);
+ int LoadPartitionTable(const struct GPTHeader & header, DiskIO & disk, uint64_t sector = 0);
+ int CheckTable(struct GPTHeader *header);
+ int SaveHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector);
+ int SavePartitionTable(DiskIO & disk, uint64_t sector);
public:
// Basic necessary functions....
GPTData(void);
@@ -155,7 +160,7 @@
// Find information about free space
uint64_t FindFirstAvailable(uint64_t start = 0);
uint64_t FindFirstInLargest(void);
- uint64_t FindLastAvailable(uint64_t start);
+ uint64_t FindLastAvailable();
uint64_t FindLastInFree(uint64_t start);
uint64_t FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment);
int IsFree(uint64_t sector);
diff --git a/gptpart.cc b/gptpart.cc
index 1cba0a0..283eb3d 100644
--- a/gptpart.cc
+++ b/gptpart.cc
@@ -145,8 +145,9 @@
cout << firstLBA << " ";
cout.width(14);
cout << lastLBA << " ";
- cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
- for (i = 0; i < 9 - (int) sizeInSI.length(); i++) cout << " ";
+ cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
+ for (i = 0; i < 10 - (int) sizeInSI.length(); i++)
+ cout << " ";
cout.fill('0');
cout.width(4);
cout.setf(ios::uppercase);
diff --git a/parttypes.cc b/parttypes.cc
index 850b1e3..1bda724 100644
--- a/parttypes.cc
+++ b/parttypes.cc
@@ -104,7 +104,7 @@
// 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(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");
@@ -191,7 +191,7 @@
} // 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) {
+PartType & PartType::operator=(uint16_t ID) {
AType* theItem = allTypes;
int found = 0;
diff --git a/parttypes.h b/parttypes.h
index 1f82d1d..5777f9c 100644
--- a/parttypes.h
+++ b/parttypes.h
@@ -46,7 +46,7 @@
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
+ PartType & operator=(uint16_t ID); // Use MBR type code times 0x0100 to assign GUID
// Retrieve transformed GUID data based on type code matches
string TypeName(void);
diff --git a/sgdisk.cc b/sgdisk.cc
index e97e57d..9b5ae92 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -140,7 +140,7 @@
saveData = 1;
break;
case 'E':
- cout << theGPT.FindLastAvailable(theGPT.FindFirstInLargest()) << "\n";
+ cout << theGPT.FindLastInFree(theGPT.FindFirstInLargest()) << "\n";
break;
case 'f':
cout << theGPT.FindFirstInLargest() << "\n";
@@ -205,7 +205,7 @@
case 't':
theGPT.JustLooking(0);
partNum = (int) GetInt(typeCode, 1) - 1;
- sscanf(GetString(typeCode, 2).c_str(), "%ux", &hexCode);
+ sscanf(GetString(typeCode, 2).c_str(), "%x", &hexCode);
if (theGPT.ChangePartType(partNum, hexCode)) {
saveData = 1;
} else {
diff --git a/support.cc b/support.cc
index 56a2dd3..f179c2f 100644
--- a/support.cc
+++ b/support.cc
@@ -234,12 +234,12 @@
char* tempValue = NULL;
int i;
- tempValue = (char*) malloc(numBytes);
+ tempValue = new char [numBytes];
if (tempValue != NULL) {
memcpy(tempValue, theValue, numBytes);
for (i = 0; i < numBytes; i++)
((char*) theValue)[i] = tempValue[numBytes - i - 1];
- free(tempValue);
+ delete[] tempValue;
} // if
} // ReverseBytes()