diff --git a/CHANGELOG b/CHANGELOG index 7139adb3a566690e2d81cc00f1b3a8bcfc52bfed..70098ce6e13d0e5cf2319918193ea99c7ad3a5bd 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 f1d1ade532a9f3b2454e0388d4dbb89e580648c9..50775558445085f921a8687733c41026d1b1fb3f 100644 --- a/bsd.cc +++ b/bsd.cc @@ -37,7 +37,7 @@ BSDData::BSDData(void) { } // 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 @@ 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 (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 8fbc7b513100a2ac572aba8806ccd83472ca493a..00ffd99d0d9db5e199a5284502fb6fe6720602bb 100644 --- a/diskio-unix.cc +++ b/diskio-unix.cc @@ -184,6 +184,7 @@ void DiskIO::DiskSync(void) { } // 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 @@ int DiskIO::Seek(uint64_t sector) { // 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 @@ int DiskIO::Read(void* buffer, int numBytes) { 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 @@ int DiskIO::Read(void* buffer, int numBytes) { if (((numBlocks * blockSize) != numBytes) && (retval > 0)) retval = numBytes; - free(tempSpace); + delete[] tempSpace; } // if (isOpen) return retval; } // DiskIO::Read() @@ -259,17 +261,14 @@ int DiskIO::Write(void* buffer, int numBytes) { 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 @@ int DiskIO::Write(void* buffer, int numBytes) { 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 e3547c64a1da449ffa152886e31c5d19f10b3593..d5cd84b0afcbcf9cd6edf48120293ecac4d2ee3b 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 @@ int DiskIO::OpenForRead(void) { 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 @@ int DiskIO::Read(void* buffer, int numBytes) { 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 @@ int DiskIO::Read(void* buffer, int numBytes) { if (((numBlocks * blockSize) != numBytes) && (retval > 0)) retval = numBytes; - free(tempSpace); + delete[] tempSpace; } // if (isOpen) return retval; } // DiskIO::Read() @@ -261,11 +264,11 @@ int DiskIO::Write(void* buffer, int numBytes) { 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 @@ int DiskIO::Write(void* buffer, int numBytes) { 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 17a44a410769ca9198cfc96cb4100ea849578f31..1bb0178d313d4a224ac796f6209cb899448eff89 100644 --- a/diskio.cc +++ b/diskio.cc @@ -43,12 +43,10 @@ DiskIO::DiskIO(void) { 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 b27e9777a195a4ec969c0d896313c9eeee6067a1..630d1b4fad200cbc3c1cc9d1ae28315628013336 100644 --- a/diskio.h +++ b/diskio.h @@ -51,7 +51,6 @@ class DiskIO { string realFilename; int isOpen; int openForWrite; - uint8_t *sectorData; #ifdef _WIN32 HANDLE fd; #else @@ -76,6 +75,7 @@ class DiskIO { 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 5a2c9050c7376e7fc358f41b2eb04b112443686e..b81a80289483fc665eaa71fdd43a5c4d131fc842 100644 --- a/gdisk.cc +++ b/gdisk.cc @@ -29,7 +29,6 @@ int main(int argc, char* argv[]) { 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 562a085b5397175dd0655f4a124635ce10943683..a2e216f5efa6fdabc2426e2adf763a57a8f43ee7 100644 --- a/gpt.cc +++ b/gpt.cc @@ -82,7 +82,7 @@ GPTData::GPTData(string filename) { // Destructor GPTData::~GPTData(void) { - free(partitions); + delete[] partitions; } // GPTData destructor /********************************************************************* @@ -342,8 +342,8 @@ int GPTData::CheckHeaderValidity(void) { } // 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 @@ int GPTData::LoadPartitions(const string & deviceFilename) { // 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; - - // 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); + int allOK, validHeaders, loadedTable = 1; - // 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); + allOK = LoadHeader(&mainHeader, myDisk, 1, &mainCrcOk); + + 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 @@ int GPTData::ForceLoadGPTData(void) { } 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 @@ int GPTData::ForceLoadGPTData(void) { // 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 @@ int GPTData::LoadMainTable(void) { // 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; + return LoadPartitionTable(secondHeader, myDisk); +} // GPTData::LoadSecondTableAsMain() + +// 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 = 1; + int retval; - if (myDisk.OpenForRead(device)) { - seekTo = secondHeader.partitionEntriesLBA; - retval = myDisk.Seek(seekTo); + 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 @@ int GPTData::SaveGPTData(int quiet) { // 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 @@ int GPTData::SaveGPTData(int quiet) { 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 @@ int GPTData::SaveGPTData(int quiet) { 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 @@ int GPTData::SaveGPTData(int quiet) { // 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 @@ int GPTData::SaveGPTBackup(const string & filename) { // 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 @@ int GPTData::SaveGPTBackup(const string & filename) { << "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 @@ int GPTData::SaveGPTBackup(const string & filename) { 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 @@ int GPTData::LoadGPTBackup(const string & filename) { // 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 @@ int GPTData::LoadGPTBackup(const string & filename) { 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 @@ void GPTData::CreatePartition(void) { if (((firstBlock = FindFirstAvailable()) != 0) && (firstFreePart < mainHeader.numParts)) { - lastBlock = FindLastAvailable(firstBlock); + lastBlock = FindLastAvailable(); firstInLargest = FindFirstInLargest(); // Get partition number.... @@ -1430,7 +1369,7 @@ int GPTData::DestroyGPT(int prompt) { } // 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 @@ int GPTData::DestroyGPT(int prompt) { 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 @@ int GPTData::SetGPTSize(uint32_t numEntries) { // 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 @@ int GPTData::SetGPTSize(uint32_t numEntries) { } // for trash = partitions; partitions = newParts; - free(trash); + delete[] trash; } // if } else { // No existing partition table; just create it partitions = newParts; @@ -2033,7 +1973,7 @@ int GPTData::ClearGPTData(void) { // Set up the partition table.... if (partitions != NULL) - free(partitions); + delete[] partitions; partitions = NULL; SetGPTSize(NUM_GPT_ENTRIES); @@ -2297,10 +2237,9 @@ uint64_t GPTData::FindFirstInLargest(void) { 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 f1225707245ae7bce3fca2a2d25e5a65ab012057..24786488c4ca980356c0da23eb352e9d2be1241a 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 @@ protected: 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 @@ public: // 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 1cba0a0f56800360f3de458b144f843d043b24d9..283eb3ddcd88d16995f21cf9f9dc7f8994464b23 100644 --- a/gptpart.cc +++ b/gptpart.cc @@ -145,8 +145,9 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) { 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 850b1e3ad8d5919e2e2991d25f43ce1a5f933e7d..1bda724476c2f3ddd5a6471d0078057620413d6e 100644 --- a/parttypes.cc +++ b/parttypes.cc @@ -104,7 +104,7 @@ void PartType::AddAllTypes(void) { // 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 @@ int PartType::AddType(uint16_t mbrType, const char * guidData, const char * name } // 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 1f82d1d71b0d5585b68a35d21cdecc37f7c08839..5777f9c6670378c4416dfe54402023f524911019 100644 --- a/parttypes.h +++ b/parttypes.h @@ -46,7 +46,7 @@ public: 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 e97e57d34143c31266a4d519b950a238fff31b06..9b5ae92db6ff996dd35216160e11b553c72810b5 100644 --- a/sgdisk.cc +++ b/sgdisk.cc @@ -140,7 +140,7 @@ int main(int argc, char *argv[]) { 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 @@ int main(int argc, char *argv[]) { 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 56a2dd3b745f03157bb7aa3fc1a13c64298b485f..f179c2fdca642e976c1743adc7d0fb190c17d454 100644 --- a/support.cc +++ b/support.cc @@ -234,12 +234,12 @@ void ReverseBytes(void* theValue, int numBytes) { 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()