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.
This commit is contained in:
19
CHANGELOG
19
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):
|
0.6.3 (2/3/2010):
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|||||||
4
bsd.cc
4
bsd.cc
@@ -37,7 +37,7 @@ BSDData::BSDData(void) {
|
|||||||
} // default constructor
|
} // default constructor
|
||||||
|
|
||||||
BSDData::~BSDData(void) {
|
BSDData::~BSDData(void) {
|
||||||
free(partitions);
|
delete[] partitions;
|
||||||
} // destructor
|
} // destructor
|
||||||
|
|
||||||
// Read BSD disklabel data from the specified device filename. This function
|
// Read BSD disklabel data from the specified device filename. This function
|
||||||
@@ -132,7 +132,7 @@ int BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSect
|
|||||||
|
|
||||||
// If the state is good, go ahead and load the main partition data....
|
// If the state is good, go ahead and load the main partition data....
|
||||||
if (state == bsd) {
|
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++) {
|
for (i = 0; i < numParts; i++) {
|
||||||
// Once again, we use the buffer, but index it using a BSDRecord
|
// Once again, we use the buffer, but index it using a BSDRecord
|
||||||
// pointer (dangerous, but effective)....
|
// pointer (dangerous, but effective)....
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ void DiskIO::DiskSync(void) {
|
|||||||
} // DiskIO::DiskSync()
|
} // DiskIO::DiskSync()
|
||||||
|
|
||||||
// Seek to the specified sector. Returns 1 on success, 0 on failure.
|
// 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 DiskIO::Seek(uint64_t sector) {
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
off_t seekTo, sought;
|
off_t seekTo, sought;
|
||||||
@@ -208,7 +209,7 @@ int DiskIO::Seek(uint64_t sector) {
|
|||||||
// size with the number of bytes read.
|
// size with the number of bytes read.
|
||||||
// Returns the number of bytes read into buffer.
|
// Returns the number of bytes read into buffer.
|
||||||
int DiskIO::Read(void* buffer, int numBytes) {
|
int DiskIO::Read(void* buffer, int numBytes) {
|
||||||
int blockSize = 512, numBlocks, retval = 0;
|
int blockSize, numBlocks, retval = 0;
|
||||||
char* tempSpace;
|
char* tempSpace;
|
||||||
|
|
||||||
// If disk isn't open, try to open it....
|
// If disk isn't open, try to open it....
|
||||||
@@ -221,11 +222,12 @@ int DiskIO::Read(void* buffer, int numBytes) {
|
|||||||
blockSize = GetBlockSize();
|
blockSize = GetBlockSize();
|
||||||
if (numBytes <= blockSize) {
|
if (numBytes <= blockSize) {
|
||||||
numBlocks = 1;
|
numBlocks = 1;
|
||||||
tempSpace = (char*) malloc(blockSize);
|
tempSpace = new char [blockSize];
|
||||||
} else {
|
} else {
|
||||||
numBlocks = numBytes / blockSize;
|
numBlocks = numBytes / blockSize;
|
||||||
if ((numBytes % blockSize) != 0) numBlocks++;
|
if ((numBytes % blockSize) != 0)
|
||||||
tempSpace = (char*) malloc(numBlocks * blockSize);
|
numBlocks++;
|
||||||
|
tempSpace = new char [numBlocks * blockSize];
|
||||||
} // if/else
|
} // if/else
|
||||||
|
|
||||||
// Read the data into temporary space, then copy it to buffer
|
// Read the data into temporary space, then copy it to buffer
|
||||||
@@ -236,7 +238,7 @@ int DiskIO::Read(void* buffer, int numBytes) {
|
|||||||
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
||||||
retval = numBytes;
|
retval = numBytes;
|
||||||
|
|
||||||
free(tempSpace);
|
delete[] tempSpace;
|
||||||
} // if (isOpen)
|
} // if (isOpen)
|
||||||
return retval;
|
return retval;
|
||||||
} // DiskIO::Read()
|
} // DiskIO::Read()
|
||||||
@@ -259,17 +261,14 @@ int DiskIO::Write(void* buffer, int numBytes) {
|
|||||||
blockSize = GetBlockSize();
|
blockSize = GetBlockSize();
|
||||||
if (numBytes <= blockSize) {
|
if (numBytes <= blockSize) {
|
||||||
numBlocks = 1;
|
numBlocks = 1;
|
||||||
tempSpace = (char*) malloc(blockSize);
|
tempSpace = new char [blockSize];
|
||||||
} else {
|
} else {
|
||||||
numBlocks = numBytes / blockSize;
|
numBlocks = numBytes / blockSize;
|
||||||
if ((numBytes % blockSize) != 0) numBlocks++;
|
if ((numBytes % blockSize) != 0) numBlocks++;
|
||||||
tempSpace = (char*) malloc(numBlocks * blockSize);
|
tempSpace = new char [numBlocks * blockSize];
|
||||||
} // if/else
|
} // if/else
|
||||||
|
|
||||||
// Copy the data to my own buffer, then write it
|
// 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);
|
memcpy(tempSpace, buffer, numBytes);
|
||||||
for (i = numBytes; i < numBlocks * blockSize; i++) {
|
for (i = numBytes; i < numBlocks * blockSize; i++) {
|
||||||
tempSpace[i] = 0;
|
tempSpace[i] = 0;
|
||||||
@@ -280,7 +279,7 @@ int DiskIO::Write(void* buffer, int numBytes) {
|
|||||||
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
||||||
retval = numBytes;
|
retval = numBytes;
|
||||||
|
|
||||||
free(tempSpace);
|
delete[] tempSpace;
|
||||||
} // if (isOpen)
|
} // if (isOpen)
|
||||||
return retval;
|
return retval;
|
||||||
} // DiskIO:Write()
|
} // DiskIO:Write()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <winioctl.h>
|
#include <winioctl.h>
|
||||||
#define fstat64 fstat
|
#define fstat64 fstat
|
||||||
#define stat64 stat
|
#define stat64 stat
|
||||||
#define S_IRGRP 0
|
//#define S_IRGRP 0
|
||||||
#define S_IROTH 0
|
#define S_IROTH 0
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -64,7 +64,9 @@ int DiskIO::OpenForRead(void) {
|
|||||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
if (fd == INVALID_HANDLE_VALUE) {
|
if (fd == INVALID_HANDLE_VALUE) {
|
||||||
CloseHandle(fd);
|
CloseHandle(fd);
|
||||||
cerr << "Problem opening " << realFilename << " for reading!\n";
|
cerr << "Problem opening ";
|
||||||
|
cerr << realFilename;
|
||||||
|
cerr << " for reading!\n";
|
||||||
realFilename = "";
|
realFilename = "";
|
||||||
userFilename = "";
|
userFilename = "";
|
||||||
isOpen = 0;
|
isOpen = 0;
|
||||||
@@ -220,11 +222,12 @@ int DiskIO::Read(void* buffer, int numBytes) {
|
|||||||
blockSize = GetBlockSize();
|
blockSize = GetBlockSize();
|
||||||
if (numBytes <= blockSize) {
|
if (numBytes <= blockSize) {
|
||||||
numBlocks = 1;
|
numBlocks = 1;
|
||||||
tempSpace = (char*) malloc(blockSize);
|
tempSpace = new char [blockSize];
|
||||||
} else {
|
} else {
|
||||||
numBlocks = numBytes / blockSize;
|
numBlocks = numBytes / blockSize;
|
||||||
if ((numBytes % blockSize) != 0) numBlocks++;
|
if ((numBytes % blockSize) != 0)
|
||||||
tempSpace = (char*) malloc(numBlocks * blockSize);
|
numBlocks++;
|
||||||
|
tempSpace = new char [numBlocks * blockSize];
|
||||||
} // if/else
|
} // if/else
|
||||||
|
|
||||||
// Read the data into temporary space, then copy it to buffer
|
// Read the data into temporary space, then copy it to buffer
|
||||||
@@ -237,7 +240,7 @@ int DiskIO::Read(void* buffer, int numBytes) {
|
|||||||
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
||||||
retval = numBytes;
|
retval = numBytes;
|
||||||
|
|
||||||
free(tempSpace);
|
delete[] tempSpace;
|
||||||
} // if (isOpen)
|
} // if (isOpen)
|
||||||
return retval;
|
return retval;
|
||||||
} // DiskIO::Read()
|
} // DiskIO::Read()
|
||||||
@@ -261,11 +264,11 @@ int DiskIO::Write(void* buffer, int numBytes) {
|
|||||||
blockSize = GetBlockSize();
|
blockSize = GetBlockSize();
|
||||||
if (numBytes <= blockSize) {
|
if (numBytes <= blockSize) {
|
||||||
numBlocks = 1;
|
numBlocks = 1;
|
||||||
tempSpace = (char*) malloc(blockSize);
|
tempSpace = new char [blockSize];
|
||||||
} else {
|
} else {
|
||||||
numBlocks = numBytes / blockSize;
|
numBlocks = numBytes / blockSize;
|
||||||
if ((numBytes % blockSize) != 0) numBlocks++;
|
if ((numBytes % blockSize) != 0) numBlocks++;
|
||||||
tempSpace = (char*) malloc(numBlocks * blockSize);
|
tempSpace = new char [numBlocks * blockSize];
|
||||||
} // if/else
|
} // if/else
|
||||||
|
|
||||||
// Copy the data to my own buffer, then write it
|
// Copy the data to my own buffer, then write it
|
||||||
@@ -282,7 +285,7 @@ int DiskIO::Write(void* buffer, int numBytes) {
|
|||||||
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
||||||
retval = numBytes;
|
retval = numBytes;
|
||||||
|
|
||||||
free(tempSpace);
|
delete[] tempSpace;
|
||||||
} // if (isOpen)
|
} // if (isOpen)
|
||||||
return retval;
|
return retval;
|
||||||
} // DiskIO:Write()
|
} // DiskIO:Write()
|
||||||
|
|||||||
@@ -43,12 +43,10 @@ DiskIO::DiskIO(void) {
|
|||||||
realFilename = "";
|
realFilename = "";
|
||||||
isOpen = 0;
|
isOpen = 0;
|
||||||
openForWrite = 0;
|
openForWrite = 0;
|
||||||
sectorData = NULL;
|
|
||||||
} // constructor
|
} // constructor
|
||||||
|
|
||||||
DiskIO::~DiskIO(void) {
|
DiskIO::~DiskIO(void) {
|
||||||
Close();
|
Close();
|
||||||
free(sectorData);
|
|
||||||
} // destructor
|
} // destructor
|
||||||
|
|
||||||
// Open a disk device for reading. Returns 1 on success, 0 on failure.
|
// Open a disk device for reading. Returns 1 on success, 0 on failure.
|
||||||
|
|||||||
2
diskio.h
2
diskio.h
@@ -51,7 +51,6 @@ class DiskIO {
|
|||||||
string realFilename;
|
string realFilename;
|
||||||
int isOpen;
|
int isOpen;
|
||||||
int openForWrite;
|
int openForWrite;
|
||||||
uint8_t *sectorData;
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HANDLE fd;
|
HANDLE fd;
|
||||||
#else
|
#else
|
||||||
@@ -76,6 +75,7 @@ class DiskIO {
|
|||||||
int FindAlignment(const string & filename);
|
int FindAlignment(const string & filename);
|
||||||
int IsOpen(void) {return isOpen;}
|
int IsOpen(void) {return isOpen;}
|
||||||
int IsOpenForWrite(void) {return openForWrite;}
|
int IsOpenForWrite(void) {return openForWrite;}
|
||||||
|
string GetName(void) {return realFilename;}
|
||||||
|
|
||||||
uint64_t DiskSize(int* err);
|
uint64_t DiskSize(int* err);
|
||||||
}; // struct GPTPart
|
}; // struct GPTPart
|
||||||
|
|||||||
1
gdisk.cc
1
gdisk.cc
@@ -29,7 +29,6 @@ int main(int argc, char* argv[]) {
|
|||||||
GPTData theGPT;
|
GPTData theGPT;
|
||||||
int doMore = 1;
|
int doMore = 1;
|
||||||
char* device = NULL;
|
char* device = NULL;
|
||||||
PartType typeHelper; // unused, but necessary to initialize partition type linked list
|
|
||||||
|
|
||||||
cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n";
|
cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n";
|
||||||
|
|
||||||
|
|||||||
419
gpt.cc
419
gpt.cc
@@ -82,7 +82,7 @@ GPTData::GPTData(string filename) {
|
|||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
GPTData::~GPTData(void) {
|
GPTData::~GPTData(void) {
|
||||||
free(partitions);
|
delete[] partitions;
|
||||||
} // GPTData destructor
|
} // GPTData destructor
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
@@ -342,8 +342,8 @@ int GPTData::CheckHeaderValidity(void) {
|
|||||||
} // GPTData::CheckHeaderValidity()
|
} // GPTData::CheckHeaderValidity()
|
||||||
|
|
||||||
// Check the header CRC to see if it's OK...
|
// Check the header CRC to see if it's OK...
|
||||||
// Note: Must be called BEFORE byte-order reversal on big-endian
|
// Note: Must be called with header in LITTLE-ENDIAN
|
||||||
// systems!
|
// (x86, x86-64, etc.) byte order.
|
||||||
int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
||||||
uint32_t oldCRC, newCRC, hSize;
|
uint32_t oldCRC, newCRC, hSize;
|
||||||
|
|
||||||
@@ -648,53 +648,22 @@ int GPTData::LoadPartitions(const string & deviceFilename) {
|
|||||||
// Loads the GPT, as much as possible. Returns 1 if this seems to have
|
// Loads the GPT, as much as possible. Returns 1 if this seems to have
|
||||||
// succeeded, 0 if there are obvious problems....
|
// succeeded, 0 if there are obvious problems....
|
||||||
int GPTData::ForceLoadGPTData(void) {
|
int GPTData::ForceLoadGPTData(void) {
|
||||||
int allOK = 1, validHeaders;
|
int allOK, validHeaders, loadedTable = 1;
|
||||||
uint64_t seekTo;
|
|
||||||
uint8_t* storage;
|
|
||||||
uint32_t newCRC, sizeOfParts;
|
|
||||||
|
|
||||||
// Seek to and read the main GPT header
|
allOK = LoadHeader(&mainHeader, myDisk, 1, &mainCrcOk);
|
||||||
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);
|
|
||||||
|
|
||||||
// Load backup header, check its CRC, and store the results of the
|
if (mainCrcOk && (mainHeader.backupLBA < diskSize)) {
|
||||||
// check for future reference. Load backup header using pointer in main
|
allOK = LoadHeader(&secondHeader, myDisk, mainHeader.backupLBA, &secondCrcOk) && allOK;
|
||||||
// header if possible; but if main header has a CRC error, or if it
|
} else {
|
||||||
// points to beyond the end of the disk, load the last sector of the
|
if (mainHeader.backupLBA >= diskSize)
|
||||||
// disk instead.
|
|
||||||
if (mainCrcOk) {
|
|
||||||
if (mainHeader.backupLBA < diskSize) {
|
|
||||||
seekTo = mainHeader.backupLBA;
|
|
||||||
} else {
|
|
||||||
seekTo = diskSize - UINT64_C(1);
|
|
||||||
cout << "Warning! Disk size is smaller than the main header indicates! Loading\n"
|
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"
|
<< "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"
|
<< "verify disk integrity, and perhaps options on the experts' menu to repair\n"
|
||||||
<< "the disk.\n";
|
<< "the disk.\n";
|
||||||
} // else
|
allOK = LoadHeader(&secondHeader, myDisk, diskSize - UINT64_C(1), &secondCrcOk) && allOK;
|
||||||
} else {
|
} // if/else
|
||||||
seekTo = diskSize - UINT64_C(1);
|
if (!allOK)
|
||||||
} // 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;
|
|
||||||
state = gpt_invalid;
|
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
|
// Return valid headers code: 0 = both headers bad; 1 = main header
|
||||||
// good, backup bad; 2 = backup header good, main header bad;
|
// good, backup bad; 2 = backup header good, main header bad;
|
||||||
@@ -734,37 +703,32 @@ int GPTData::ForceLoadGPTData(void) {
|
|||||||
} else { // bad main header CRC and backup header CRC is OK
|
} else { // bad main header CRC and backup header CRC is OK
|
||||||
state = gpt_corrupt;
|
state = gpt_corrupt;
|
||||||
if (LoadSecondTableAsMain()) {
|
if (LoadSecondTableAsMain()) {
|
||||||
|
loadedTable = 2;
|
||||||
cerr << "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n";
|
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....
|
} else { // backup table bad, bad main header CRC, but try main table in desperation....
|
||||||
if (LoadMainTable() == 0) {
|
if (LoadMainTable() == 0) {
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
|
loadedTable = 0;
|
||||||
cerr << "\a\aWarning! Unable to load either main or backup partition table!\n";
|
cerr << "\a\aWarning! Unable to load either main or backup partition table!\n";
|
||||||
} // if
|
} // if
|
||||||
} // if/else (LoadSecondTableAsMain())
|
} // if/else (LoadSecondTableAsMain())
|
||||||
} // if/else (load partition table)
|
} // if/else (load partition table)
|
||||||
|
|
||||||
// Load backup partition table into temporary storage to check
|
if (loadedTable == 1)
|
||||||
// its CRC and store the results, then discard this temporary
|
secondPartsCrcOk = CheckTable(&secondHeader);
|
||||||
// storage, since we don't use it in any but recovery operations
|
else if (loadedTable == 2)
|
||||||
seekTo = secondHeader.partitionEntriesLBA;
|
mainPartsCrcOk = CheckTable(&mainHeader);
|
||||||
if ((myDisk.Seek(seekTo)) && (secondCrcOk)) {
|
else
|
||||||
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
|
mainPartsCrcOk = secondPartsCrcOk = 0;
|
||||||
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
|
|
||||||
|
|
||||||
// Problem with main partition table; if backup is OK, use it instead....
|
// Problem with main partition table; if backup is OK, use it instead....
|
||||||
if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) {
|
if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) {
|
||||||
state = gpt_corrupt;
|
state = gpt_corrupt;
|
||||||
allOK = allOK && LoadSecondTableAsMain();
|
allOK = allOK && LoadSecondTableAsMain();
|
||||||
|
mainPartsCrcOk = 0; // LoadSecondTableAsMain() resets this, so re-flag as bad
|
||||||
cerr << "\aWarning! Main partition table CRC mismatch! Loaded backup "
|
cerr << "\aWarning! Main partition table CRC mismatch! Loaded backup "
|
||||||
<< "partition table\ninstead of main partition table!\n\n";
|
<< "partition table\ninstead of main partition table!\n\n";
|
||||||
} // if
|
} // if */
|
||||||
|
|
||||||
// Check for valid CRCs and warn if there are problems
|
// Check for valid CRCs and warn if there are problems
|
||||||
if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) ||
|
if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) ||
|
||||||
@@ -783,28 +747,7 @@ int GPTData::ForceLoadGPTData(void) {
|
|||||||
// sensible!
|
// sensible!
|
||||||
// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
|
// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
|
||||||
int GPTData::LoadMainTable(void) {
|
int GPTData::LoadMainTable(void) {
|
||||||
int retval = 1;
|
return LoadPartitionTable(mainHeader, myDisk);
|
||||||
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;
|
|
||||||
} // GPTData::LoadMainTable()
|
} // GPTData::LoadMainTable()
|
||||||
|
|
||||||
// Load the second (backup) partition table as the primary partition
|
// Load the second (backup) partition table as the primary partition
|
||||||
@@ -812,47 +755,103 @@ int GPTData::LoadMainTable(void) {
|
|||||||
// partition table is damaged.
|
// partition table is damaged.
|
||||||
// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
|
// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
|
||||||
int GPTData::LoadSecondTableAsMain(void) {
|
int GPTData::LoadSecondTableAsMain(void) {
|
||||||
uint64_t seekTo;
|
return LoadPartitionTable(secondHeader, myDisk);
|
||||||
uint32_t sizeOfParts, newCRC;
|
} // GPTData::LoadSecondTableAsMain()
|
||||||
int retval = 1;
|
|
||||||
|
|
||||||
if (myDisk.OpenForRead(device)) {
|
// Load a single GPT header (main or backup) from the specified disk device and
|
||||||
seekTo = secondHeader.partitionEntriesLBA;
|
// sector. Applies byte-order corrections on big-endian platforms. Sets crcOk
|
||||||
retval = myDisk.Seek(seekTo);
|
// 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) {
|
if (retval == 1) {
|
||||||
SetGPTSize(secondHeader.numParts);
|
SetGPTSize(header.numParts);
|
||||||
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
|
sizeOfParts = header.numParts * header.sizeOfPartitionEntries;
|
||||||
if (myDisk.Read(partitions, sizeOfParts) != (int) sizeOfParts) {
|
if (disk.Read(partitions, sizeOfParts) != (int) sizeOfParts) {
|
||||||
cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n";
|
cerr << "Warning! Read error " << errno << "! Misbehavior now likely!\n";
|
||||||
retval = 0;
|
retval = 0;
|
||||||
} // if
|
} // if
|
||||||
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
|
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
|
||||||
secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
|
mainPartsCrcOk = secondPartsCrcOk = (newCRC == header.partitionEntriesCRC);
|
||||||
mainPartsCrcOk = secondPartsCrcOk;
|
|
||||||
if (IsLittleEndian() == 0)
|
if (IsLittleEndian() == 0)
|
||||||
ReversePartitionBytes();
|
ReversePartitionBytes();
|
||||||
if (!secondPartsCrcOk) {
|
if (!mainPartsCrcOk) {
|
||||||
cout << "Caution! After loading backup partitions, the CRC still doesn't check out!\n";
|
cout << "Caution! After loading partitions, the CRC doesn't check out!\n";
|
||||||
} // if
|
} // if
|
||||||
} else {
|
} else {
|
||||||
cerr << "Error! Couldn't seek to backup partition table!\n";
|
cerr << "Error! Couldn't seek to partition table!\n";
|
||||||
} // if/else
|
} // if/else
|
||||||
} else {
|
} else {
|
||||||
cerr << "Error! Couldn't open device " << device
|
cerr << "Error! Couldn't open device " << device
|
||||||
<< " when recovering backup partition table!\n";
|
<< " when reading partition table!\n";
|
||||||
retval = 0;
|
retval = 0;
|
||||||
} // if/else
|
} // if/else
|
||||||
return retval;
|
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
|
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
|
||||||
// write, 0 if there was a problem.
|
// write, 0 if there was a problem.
|
||||||
int GPTData::SaveGPTData(int quiet) {
|
int GPTData::SaveGPTData(int quiet) {
|
||||||
int allOK = 1, littleEndian;
|
int allOK = 1, littleEndian;
|
||||||
char answer;
|
char answer;
|
||||||
uint64_t secondTable;
|
// uint64_t secondTable;
|
||||||
uint32_t numParts;
|
uint32_t numParts;
|
||||||
uint64_t offset;
|
|
||||||
|
|
||||||
littleEndian = IsLittleEndian();
|
littleEndian = IsLittleEndian();
|
||||||
|
|
||||||
@@ -907,18 +906,8 @@ int GPTData::SaveGPTData(int quiet) {
|
|||||||
// Pull out some data that's needed before doing byte-order reversal on
|
// Pull out some data that's needed before doing byte-order reversal on
|
||||||
// big-endian systems....
|
// big-endian systems....
|
||||||
numParts = mainHeader.numParts;
|
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();
|
RecomputeCRCs();
|
||||||
/* ReverseHeaderBytes(&mainHeader);
|
|
||||||
ReverseHeaderBytes(&secondHeader);
|
|
||||||
ReversePartitionBytes(); */
|
|
||||||
|
|
||||||
if ((allOK) && (!quiet)) {
|
if ((allOK) && (!quiet)) {
|
||||||
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"
|
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"
|
||||||
@@ -938,59 +927,22 @@ int GPTData::SaveGPTData(int quiet) {
|
|||||||
|
|
||||||
if (allOK && myDisk.OpenForWrite(device)) {
|
if (allOK && myDisk.OpenForWrite(device)) {
|
||||||
// Now write the main GPT header...
|
// Now write the main GPT header...
|
||||||
if (myDisk.Seek(1) == 1) {
|
allOK = SaveHeader(&mainHeader, myDisk, 1);
|
||||||
if (!littleEndian)
|
|
||||||
ReverseHeaderBytes(&mainHeader);
|
|
||||||
if (myDisk.Write(&mainHeader, 512) != 512)
|
|
||||||
allOK = 0;
|
|
||||||
if (!littleEndian)
|
|
||||||
ReverseHeaderBytes(&mainHeader);
|
|
||||||
} else allOK = 0; // if (myDisk.Seek()...)
|
|
||||||
|
|
||||||
// Now write the main partition tables...
|
// Now write the main partition tables...
|
||||||
if (allOK) {
|
if (allOK) {
|
||||||
offset = mainHeader.partitionEntriesLBA;
|
allOK = SavePartitionTable(myDisk, mainHeader.partitionEntriesLBA);
|
||||||
if (myDisk.Seek(offset)) {
|
|
||||||
if (!littleEndian)
|
|
||||||
ReversePartitionBytes();
|
|
||||||
if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
|
|
||||||
allOK = 0;
|
|
||||||
if (!littleEndian)
|
|
||||||
ReversePartitionBytes();
|
|
||||||
} else allOK = 0; // if (myDisk.Seek()...)
|
|
||||||
} // if (allOK)
|
} // if (allOK)
|
||||||
|
|
||||||
// Now seek to near the end to write the secondary GPT....
|
// Now seek to near the end to write the secondary GPT....
|
||||||
if (allOK) {
|
allOK = SavePartitionTable(myDisk, secondHeader.partitionEntriesLBA);
|
||||||
offset = (uint64_t) secondTable;
|
if (!allOK)
|
||||||
if (myDisk.Seek(offset) != 1) {
|
cerr << "Unable to save backup partition table! Perhaps the 'e' option on the experts'\n"
|
||||||
allOK = 0;
|
<< "menu will resolve this problem.\n";
|
||||||
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)
|
|
||||||
|
|
||||||
// Now write the secondary GPT header...
|
// Now write the secondary GPT header...
|
||||||
if (allOK) {
|
if (allOK) {
|
||||||
offset = mainHeader.backupLBA;
|
allOK = SaveHeader(&secondHeader, myDisk, 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);
|
|
||||||
} // if (allOK)
|
} // if (allOK)
|
||||||
|
|
||||||
// re-read the partition table
|
// re-read the partition table
|
||||||
@@ -1015,14 +967,6 @@ int GPTData::SaveGPTData(int quiet) {
|
|||||||
cout << "Aborting write of new partition table.\n";
|
cout << "Aborting write of new partition table.\n";
|
||||||
} // if
|
} // 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);
|
return (allOK);
|
||||||
} // GPTData::SaveGPTData()
|
} // GPTData::SaveGPTData()
|
||||||
|
|
||||||
@@ -1034,7 +978,6 @@ int GPTData::SaveGPTData(int quiet) {
|
|||||||
// identical to the main partition table on healthy disks.
|
// identical to the main partition table on healthy disks.
|
||||||
int GPTData::SaveGPTBackup(const string & filename) {
|
int GPTData::SaveGPTBackup(const string & filename) {
|
||||||
int allOK = 1;
|
int allOK = 1;
|
||||||
uint32_t numParts;
|
|
||||||
DiskIO backupFile;
|
DiskIO backupFile;
|
||||||
|
|
||||||
if (backupFile.OpenForWrite(filename)) {
|
if (backupFile.OpenForWrite(filename)) {
|
||||||
@@ -1044,35 +987,19 @@ int GPTData::SaveGPTBackup(const string & filename) {
|
|||||||
// backup. I'm favoring misses over false alarms....
|
// backup. I'm favoring misses over false alarms....
|
||||||
RecomputeCRCs();
|
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);
|
protectiveMBR.WriteMBRData(&backupFile);
|
||||||
|
|
||||||
// Now write the main GPT header...
|
if (allOK) {
|
||||||
if (allOK)
|
|
||||||
// MBR write closed disk, so re-open and seek to end....
|
// MBR write closed disk, so re-open and seek to end....
|
||||||
backupFile.OpenForWrite();
|
backupFile.OpenForWrite();
|
||||||
backupFile.Seek(1);
|
allOK = SaveHeader(&mainHeader, backupFile, 1);
|
||||||
if (backupFile.Write(&mainHeader, 512) == -1)
|
} // if (allOK)
|
||||||
allOK = 0;
|
|
||||||
|
|
||||||
// Now write the secondary GPT header...
|
|
||||||
if (allOK)
|
if (allOK)
|
||||||
if (backupFile.Write(&secondHeader, 512) == -1)
|
allOK = SaveHeader(&secondHeader, backupFile, 2);
|
||||||
allOK = 0;
|
|
||||||
|
|
||||||
// Now write the main partition tables...
|
if (allOK)
|
||||||
if (allOK) {
|
allOK = SavePartitionTable(backupFile, 3);
|
||||||
if (backupFile.Write(partitions, GPT_SIZE * numParts) == -1)
|
|
||||||
allOK = 0;
|
|
||||||
} // if
|
|
||||||
|
|
||||||
if (allOK) { // writes completed OK
|
if (allOK) { // writes completed OK
|
||||||
cout << "The operation has completed successfully.\n";
|
cout << "The operation has completed successfully.\n";
|
||||||
@@ -1081,13 +1008,6 @@ int GPTData::SaveGPTBackup(const string & filename) {
|
|||||||
<< "It may not be usable!\n";
|
<< "It may not be usable!\n";
|
||||||
} // if/else
|
} // if/else
|
||||||
backupFile.Close();
|
backupFile.Close();
|
||||||
|
|
||||||
// Now reverse the byte-order reversal, if necessary....
|
|
||||||
if (IsLittleEndian() == 0) {
|
|
||||||
ReverseHeaderBytes(&mainHeader);
|
|
||||||
ReverseHeaderBytes(&secondHeader);
|
|
||||||
ReversePartitionBytes();
|
|
||||||
} // if
|
|
||||||
} else {
|
} else {
|
||||||
cerr << "Unable to open file " << filename << " for writing! Aborting!\n";
|
cerr << "Unable to open file " << filename << " for writing! Aborting!\n";
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
@@ -1095,14 +1015,54 @@ int GPTData::SaveGPTBackup(const string & filename) {
|
|||||||
return allOK;
|
return allOK;
|
||||||
} // GPTData::SaveGPTBackup()
|
} // 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
|
// Load GPT data from a backup file created by SaveGPTBackup(). This function
|
||||||
// does minimal error checking. It returns 1 if it completed successfully,
|
// 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
|
// 0 if there was a problem. In the latter case, it creates a new empty
|
||||||
// set of partitions.
|
// set of partitions.
|
||||||
int GPTData::LoadGPTBackup(const string & filename) {
|
int GPTData::LoadGPTBackup(const string & filename) {
|
||||||
int allOK = 1, val;
|
int allOK = 1, val, err;
|
||||||
uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC;
|
uint32_t numParts, sizeOfEntries;
|
||||||
int littleEndian = 1;
|
int littleEndian = 1, shortBackup = 0;
|
||||||
DiskIO backupFile;
|
DiskIO backupFile;
|
||||||
|
|
||||||
if (backupFile.OpenForRead(filename)) {
|
if (backupFile.OpenForRead(filename)) {
|
||||||
@@ -1112,29 +1072,20 @@ int GPTData::LoadGPTBackup(const string & filename) {
|
|||||||
// Let the MBRData class load the saved MBR...
|
// Let the MBRData class load the saved MBR...
|
||||||
protectiveMBR.ReadMBRData(&backupFile, 0); // 0 = don't check block size
|
protectiveMBR.ReadMBRData(&backupFile, 0); // 0 = don't check block size
|
||||||
|
|
||||||
// Load the main GPT header, check its vaility, and set the GPT
|
LoadHeader(&mainHeader, backupFile, 1, &mainCrcOk);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Reverse byte order, if necessary
|
// Check backup file size and rebuild second header if file is right
|
||||||
if (littleEndian == 0) {
|
// size to be direct dd copy of MBR, main header, and main partition
|
||||||
ReverseHeaderBytes(&mainHeader);
|
// table; if other size, treat it like a GPT fdisk-generated backup
|
||||||
} // if
|
// file
|
||||||
|
shortBackup = ((backupFile.DiskSize(&err) * backupFile.GetBlockSize()) ==
|
||||||
// Load the backup GPT header in much the same way as the main
|
(mainHeader.numParts * mainHeader.sizeOfPartitionEntries) + 1024);
|
||||||
// GPT header....
|
if (shortBackup) {
|
||||||
if (backupFile.Read(&secondHeader, 512) != 512) {
|
RebuildSecondHeader();
|
||||||
cerr << "Warning! Read error " << errno << "; strange behavior now likely!\n";
|
secondCrcOk = mainCrcOk;
|
||||||
} // if
|
} else {
|
||||||
secondCrcOk = CheckHeaderCRC(&secondHeader);
|
LoadHeader(&secondHeader, backupFile, 2, &secondCrcOk);
|
||||||
|
} // if/else
|
||||||
// Reverse byte order, if necessary
|
|
||||||
if (littleEndian == 0) {
|
|
||||||
ReverseHeaderBytes(&secondHeader);
|
|
||||||
} // if
|
|
||||||
|
|
||||||
// Return valid headers code: 0 = both headers bad; 1 = main header
|
// Return valid headers code: 0 = both headers bad; 1 = main header
|
||||||
// good, backup bad; 2 = backup header good, main header bad;
|
// good, backup bad; 2 = backup header good, main header bad;
|
||||||
@@ -1152,27 +1103,15 @@ int GPTData::LoadGPTBackup(const string & filename) {
|
|||||||
|
|
||||||
SetGPTSize(numParts);
|
SetGPTSize(numParts);
|
||||||
|
|
||||||
// If current disk size doesn't match that of backup....
|
|
||||||
if (secondHeader.currentLBA != diskSize - UINT64_C(1)) {
|
if (secondHeader.currentLBA != diskSize - UINT64_C(1)) {
|
||||||
cout << "Warning! Current disk size doesn't match that of the backup!\n"
|
cout << "Warning! Current disk size doesn't match that of the backup!\n"
|
||||||
<< "Adjusting sizes to match, but subsequent problems are possible!\n";
|
<< "Adjusting sizes to match, but subsequent problems are possible!\n";
|
||||||
MoveSecondHeaderToEnd();
|
MoveSecondHeaderToEnd();
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// Load main partition table, and record whether its CRC
|
if (!LoadPartitionTable(mainHeader, backupFile, (uint64_t) (3 - shortBackup)))
|
||||||
// matches the stored value
|
cerr << "Warning! Read error " << errno
|
||||||
sizeOfParts = numParts * sizeOfEntries;
|
<< " loading partition table; strange behavior now likely!\n";
|
||||||
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
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
@@ -1318,7 +1257,7 @@ void GPTData::CreatePartition(void) {
|
|||||||
|
|
||||||
if (((firstBlock = FindFirstAvailable()) != 0) &&
|
if (((firstBlock = FindFirstAvailable()) != 0) &&
|
||||||
(firstFreePart < mainHeader.numParts)) {
|
(firstFreePart < mainHeader.numParts)) {
|
||||||
lastBlock = FindLastAvailable(firstBlock);
|
lastBlock = FindLastAvailable();
|
||||||
firstInLargest = FindFirstInLargest();
|
firstInLargest = FindFirstInLargest();
|
||||||
|
|
||||||
// Get partition number....
|
// Get partition number....
|
||||||
@@ -1430,7 +1369,7 @@ int GPTData::DestroyGPT(int prompt) {
|
|||||||
} // if
|
} // if
|
||||||
myDisk.Seek(mainHeader.partitionEntriesLBA); // seek to partition table
|
myDisk.Seek(mainHeader.partitionEntriesLBA); // seek to partition table
|
||||||
tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
|
tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
|
||||||
emptyTable = (uint8_t*) malloc(tableSize);
|
emptyTable = new uint8_t[tableSize];
|
||||||
for (i = 0; i < tableSize; i++)
|
for (i = 0; i < tableSize; i++)
|
||||||
emptyTable[i] = 0;
|
emptyTable[i] = 0;
|
||||||
sum = myDisk.Write(emptyTable, tableSize);
|
sum = myDisk.Write(emptyTable, tableSize);
|
||||||
@@ -1466,6 +1405,7 @@ int GPTData::DestroyGPT(int prompt) {
|
|||||||
myDisk.Close();
|
myDisk.Close();
|
||||||
cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n"
|
cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n"
|
||||||
<< "other utilities. Program will now terminate.\n";
|
<< "other utilities. Program will now terminate.\n";
|
||||||
|
delete[] emptyTable;
|
||||||
} else {
|
} else {
|
||||||
cerr << "Problem opening " << device << " for writing! Program will now terminate.\n";
|
cerr << "Problem opening " << device << " for writing! Program will now terminate.\n";
|
||||||
} // if/else (fd != -1)
|
} // if/else (fd != -1)
|
||||||
@@ -1894,7 +1834,7 @@ int GPTData::SetGPTSize(uint32_t numEntries) {
|
|||||||
// data.
|
// data.
|
||||||
if ((numEntries != mainHeader.numParts) || (numEntries != secondHeader.numParts)
|
if ((numEntries != mainHeader.numParts) || (numEntries != secondHeader.numParts)
|
||||||
|| (partitions == NULL)) {
|
|| (partitions == NULL)) {
|
||||||
newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart));
|
newParts = new GPTPart [numEntries * sizeof (GPTPart)];
|
||||||
if (newParts != NULL) {
|
if (newParts != NULL) {
|
||||||
if (partitions != NULL) { // existing partitions; copy them over
|
if (partitions != NULL) { // existing partitions; copy them over
|
||||||
GetPartRange(&i, &high);
|
GetPartRange(&i, &high);
|
||||||
@@ -1914,7 +1854,7 @@ int GPTData::SetGPTSize(uint32_t numEntries) {
|
|||||||
} // for
|
} // for
|
||||||
trash = partitions;
|
trash = partitions;
|
||||||
partitions = newParts;
|
partitions = newParts;
|
||||||
free(trash);
|
delete[] trash;
|
||||||
} // if
|
} // if
|
||||||
} else { // No existing partition table; just create it
|
} else { // No existing partition table; just create it
|
||||||
partitions = newParts;
|
partitions = newParts;
|
||||||
@@ -2033,7 +1973,7 @@ int GPTData::ClearGPTData(void) {
|
|||||||
|
|
||||||
// Set up the partition table....
|
// Set up the partition table....
|
||||||
if (partitions != NULL)
|
if (partitions != NULL)
|
||||||
free(partitions);
|
delete[] partitions;
|
||||||
partitions = NULL;
|
partitions = NULL;
|
||||||
SetGPTSize(NUM_GPT_ENTRIES);
|
SetGPTSize(NUM_GPT_ENTRIES);
|
||||||
|
|
||||||
@@ -2297,10 +2237,9 @@ uint64_t GPTData::FindFirstInLargest(void) {
|
|||||||
return selectedSegment;
|
return selectedSegment;
|
||||||
} // GPTData::FindFirstInLargest()
|
} // GPTData::FindFirstInLargest()
|
||||||
|
|
||||||
// Find the last available block on the disk at or after the start
|
// Find the last available block on the disk.
|
||||||
// block. Returns 0 if there are no available partitions after
|
// Returns 0 if there are no available partitions
|
||||||
// (or including) start.
|
uint64_t GPTData::FindLastAvailable(void) {
|
||||||
uint64_t GPTData::FindLastAvailable(uint64_t start) {
|
|
||||||
uint64_t last;
|
uint64_t last;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int lastMoved = 0;
|
int lastMoved = 0;
|
||||||
|
|||||||
11
gpt.h
11
gpt.h
@@ -8,7 +8,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "gptpart.h"
|
#include "gptpart.h"
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
#include "parttypes.h"
|
|
||||||
#include "mbr.h"
|
#include "mbr.h"
|
||||||
#include "bsd.h"
|
#include "bsd.h"
|
||||||
#include "gptpart.h"
|
#include "gptpart.h"
|
||||||
@@ -16,7 +15,7 @@
|
|||||||
#ifndef __GPTSTRUCTS
|
#ifndef __GPTSTRUCTS
|
||||||
#define __GPTSTRUCTS
|
#define __GPTSTRUCTS
|
||||||
|
|
||||||
#define GPTFDISK_VERSION "0.6.3"
|
#define GPTFDISK_VERSION "0.6.4-pre1"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -74,6 +73,12 @@ protected:
|
|||||||
int sectorAlignment; // Start & end partitions at multiples of sectorAlignment
|
int sectorAlignment; // Start & end partitions at multiples of sectorAlignment
|
||||||
int beQuiet;
|
int beQuiet;
|
||||||
WhichToUse whichWasUsed;
|
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:
|
public:
|
||||||
// Basic necessary functions....
|
// Basic necessary functions....
|
||||||
GPTData(void);
|
GPTData(void);
|
||||||
@@ -155,7 +160,7 @@ public:
|
|||||||
// Find information about free space
|
// Find information about free space
|
||||||
uint64_t FindFirstAvailable(uint64_t start = 0);
|
uint64_t FindFirstAvailable(uint64_t start = 0);
|
||||||
uint64_t FindFirstInLargest(void);
|
uint64_t FindFirstInLargest(void);
|
||||||
uint64_t FindLastAvailable(uint64_t start);
|
uint64_t FindLastAvailable();
|
||||||
uint64_t FindLastInFree(uint64_t start);
|
uint64_t FindLastInFree(uint64_t start);
|
||||||
uint64_t FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment);
|
uint64_t FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment);
|
||||||
int IsFree(uint64_t sector);
|
int IsFree(uint64_t sector);
|
||||||
|
|||||||
@@ -145,8 +145,9 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
|
|||||||
cout << firstLBA << " ";
|
cout << firstLBA << " ";
|
||||||
cout.width(14);
|
cout.width(14);
|
||||||
cout << lastLBA << " ";
|
cout << lastLBA << " ";
|
||||||
cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
|
cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
|
||||||
for (i = 0; i < 9 - (int) sizeInSI.length(); i++) cout << " ";
|
for (i = 0; i < 10 - (int) sizeInSI.length(); i++)
|
||||||
|
cout << " ";
|
||||||
cout.fill('0');
|
cout.fill('0');
|
||||||
cout.width(4);
|
cout.width(4);
|
||||||
cout.setf(ios::uppercase);
|
cout.setf(ios::uppercase);
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ void PartType::AddAllTypes(void) {
|
|||||||
// FreeBSD partition types....
|
// FreeBSD partition types....
|
||||||
// Note: Rather than extract FreeBSD disklabel data, convert FreeBSD
|
// Note: Rather than extract FreeBSD disklabel data, convert FreeBSD
|
||||||
// partitions in-place, and let FreeBSD sort out the details....
|
// 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(0xa501, "83BD6B9D-7F41-11DC-BE0B-001560B84F0F", "FreeBSD boot");
|
||||||
AddType(0xa502, "516E7CB5-6ECF-11D6-8FF8-00022D09712B", "FreeBSD swap");
|
AddType(0xa502, "516E7CB5-6ECF-11D6-8FF8-00022D09712B", "FreeBSD swap");
|
||||||
AddType(0xa503, "516E7CB6-6ECF-11D6-8FF8-00022D09712B", "FreeBSD UFS");
|
AddType(0xa503, "516E7CB6-6ECF-11D6-8FF8-00022D09712B", "FreeBSD UFS");
|
||||||
@@ -191,7 +191,7 @@ int PartType::AddType(uint16_t mbrType, const char * guidData, const char * name
|
|||||||
} // GUID::AddType(const char* variant)
|
} // GUID::AddType(const char* variant)
|
||||||
|
|
||||||
// Assign a GUID based on my custom 2-byte (16-bit) MBR hex ID 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;
|
AType* theItem = allTypes;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
GUIDData & operator=(const char * orig) {return GUIDData::operator=(orig);}
|
GUIDData & operator=(const char * orig) {return GUIDData::operator=(orig);}
|
||||||
|
|
||||||
// New data assignment
|
// 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
|
// Retrieve transformed GUID data based on type code matches
|
||||||
string TypeName(void);
|
string TypeName(void);
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ int main(int argc, char *argv[]) {
|
|||||||
saveData = 1;
|
saveData = 1;
|
||||||
break;
|
break;
|
||||||
case 'E':
|
case 'E':
|
||||||
cout << theGPT.FindLastAvailable(theGPT.FindFirstInLargest()) << "\n";
|
cout << theGPT.FindLastInFree(theGPT.FindFirstInLargest()) << "\n";
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
cout << theGPT.FindFirstInLargest() << "\n";
|
cout << theGPT.FindFirstInLargest() << "\n";
|
||||||
@@ -205,7 +205,7 @@ int main(int argc, char *argv[]) {
|
|||||||
case 't':
|
case 't':
|
||||||
theGPT.JustLooking(0);
|
theGPT.JustLooking(0);
|
||||||
partNum = (int) GetInt(typeCode, 1) - 1;
|
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)) {
|
if (theGPT.ChangePartType(partNum, hexCode)) {
|
||||||
saveData = 1;
|
saveData = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -234,12 +234,12 @@ void ReverseBytes(void* theValue, int numBytes) {
|
|||||||
char* tempValue = NULL;
|
char* tempValue = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
tempValue = (char*) malloc(numBytes);
|
tempValue = new char [numBytes];
|
||||||
if (tempValue != NULL) {
|
if (tempValue != NULL) {
|
||||||
memcpy(tempValue, theValue, numBytes);
|
memcpy(tempValue, theValue, numBytes);
|
||||||
for (i = 0; i < numBytes; i++)
|
for (i = 0; i < numBytes; i++)
|
||||||
((char*) theValue)[i] = tempValue[numBytes - i - 1];
|
((char*) theValue)[i] = tempValue[numBytes - i - 1];
|
||||||
free(tempValue);
|
delete[] tempValue;
|
||||||
} // if
|
} // if
|
||||||
} // ReverseBytes()
|
} // ReverseBytes()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user