From 247657a5acbb7eb21c336ba84a68b801b7c19be0 Mon Sep 17 00:00:00 2001 From: srs5694 <srs5694@users.sourceforge.net> Date: Thu, 26 Nov 2009 18:36:12 -0500 Subject: [PATCH] 0.5.1-pre3; more bug fixes related to handling of mislocated secondary header and partition table. --- CHANGELOG | 4 ++ gdisk.cc | 4 +- gpt.cc | 111 ++++++++++++++++++++++++++++++----------------------- gpt.h | 2 +- support.cc | 3 +- 5 files changed, 73 insertions(+), 51 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c853e5b..9667715 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,10 @@ - Added 'e' option (relocate backup GPT data structures) to the experts' menu. +- Fixed bug that prevented recovery of partitions in case of partially + damaged GPT data (bad main and good backup or bad backup and good + main header, for instance). + 0.5.0: ------ diff --git a/gdisk.cc b/gdisk.cc index ef42ea8..bfee217 100644 --- a/gdisk.cc +++ b/gdisk.cc @@ -29,7 +29,7 @@ int main(int argc, char* argv[]) { int doMore = 1; char* device = NULL; - printf("GPT fdisk (gdisk) version 0.5.1-pre2\n\n"); + printf("GPT fdisk (gdisk) version 0.5.1-pre3\n\n"); if (argc == 2) { // basic usage if (SizesOK()) { @@ -311,7 +311,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) { break; case 'e': case 'E': printf("Relocating backup data structures to the end of the disk\n"); - theGPT->FixSecondHeaderLocation(); + theGPT->MoveSecondHeaderToEnd(); break; case 'g': case 'G': printf("Enter the disk's unique GUID:\n"); diff --git a/gpt.cc b/gpt.cc index f339a72..2e99714 100644 --- a/gpt.cc +++ b/gpt.cc @@ -124,8 +124,8 @@ int GPTData::Verify(void) { problems++; printf("\nProblem: The secondary header's self-pointer indicates that it doesn't reside\n" "at the end of the disk. If you've added a disk to a RAID array, use the 'e'\n" - "option on the experts' menu to adjust the secondary header's and partition" - "table's locations."); + "option on the experts' menu to adjust the secondary header's and partition\n" + "table's locations.\n"); } // if // Now check that critical main and backup GPT entries match each other @@ -676,7 +676,7 @@ int GPTData::ForceLoadGPTData(int fd) { return allOK; } // GPTData::ForceLoadGPTData() -// Loads the partition tables pointed to by the main GPT header. The +// Loads the partition table pointed to by the main GPT header. The // main GPT header in memory MUST be valid for this call to do anything // sensible! int GPTData::LoadMainTable(void) { @@ -753,12 +753,24 @@ int GPTData::SaveGPTData(void) { // Check that disk is really big enough to handle this... if (mainHeader.backupLBA > diskSize) { - fprintf(stderr, "Error! Disk is too small -- either the original MBR is corrupt or you're\n"); - fprintf(stderr, "working from an MBR copied to a file! Aborting!\n"); + fprintf(stderr, "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n" + "problem (or it might not). Aborting!\n"); printf("(Disk size is %ld sectors, needs to be %ld sectors.)\n", diskSize, mainHeader.backupLBA); allOK = 0; } // if + // Check that second header is properly placed. Warn and ask if this should + // be corrected if the test fails.... + if (mainHeader.backupLBA < (diskSize - UINT64_C(1))) { + printf("Warning! Secondary header is placed too early on the disk! Do you want to\n" + "correct this problem? "); + if (GetYN() == 'Y') { + MoveSecondHeaderToEnd(); + printf("Have moved second header and partition table to correct location.\n"); + } else { + printf("Have not corrected the problem. Strange problems may occur in the future!\n"); + } // if correction requested + } // if // Check for overlapping partitions.... if (FindOverlaps() > 0) { @@ -988,10 +1000,7 @@ int GPTData::LoadGPTBackup(char* filename) { if (secondHeader.currentLBA != diskSize - UINT64_C(1)) { printf("Warning! Current disk size doesn't match that of the backup!\n" "Adjusting sizes to match, but subsequent problems are possible!\n"); - secondHeader.currentLBA = mainHeader.backupLBA = diskSize - UINT64_C(1); - mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; - secondHeader.lastUsableLBA = mainHeader.lastUsableLBA; - secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); + MoveSecondHeaderToEnd(); } // if // Load main partition table, and record whether its CRC @@ -1398,6 +1407,7 @@ WhichToUse GPTData::UseWhichPartitions(void) { "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n" "verification and recovery are STRONGLY recommended.\n" "****************************************************************************\n"); + which = use_gpt; } // if/else/else } // if (corrupt GPT) @@ -1703,42 +1713,47 @@ int GPTData::SetGPTSize(uint32_t numEntries) { printf("to %lu to fill the sector\n", (unsigned long) numEntries); } // if - newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart)); - if (newParts != NULL) { - if (partitions != NULL) { // existing partitions; copy them over - GetPartRange(&i, &high); - if (numEntries < (high + 1)) { // Highest entry too high for new # - printf("The highest-numbered partition is %lu, which is greater than the requested\n" - "partition table size of %d; cannot resize. Perhaps sorting will help.\n", - (unsigned long) (high + 1), numEntries); - allOK = 0; - } else { // go ahead with copy - if (numEntries < mainHeader.numParts) - copyNum = numEntries; - else - copyNum = mainHeader.numParts; - for (i = 0; i < copyNum; i++) { - newParts[i] = partitions[i]; - } // for - trash = partitions; + // Do the work only if the # of partitions is changing. Along with being + // efficient, this prevents mucking the with location of the secondary + // partition table, which causes problems when loading data from a RAID + // array that's been expanded because this function is called when loading + // data. + if ((numEntries != mainHeader.numParts) || (partitions == NULL)) { + newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart)); + if (newParts != NULL) { + if (partitions != NULL) { // existing partitions; copy them over + GetPartRange(&i, &high); + if (numEntries < (high + 1)) { // Highest entry too high for new # + printf("The highest-numbered partition is %lu, which is greater than the requested\n" + "partition table size of %d; cannot resize. Perhaps sorting will help.\n", + (unsigned long) (high + 1), numEntries); + allOK = 0; + } else { // go ahead with copy + if (numEntries < mainHeader.numParts) + copyNum = numEntries; + else + copyNum = mainHeader.numParts; + for (i = 0; i < copyNum; i++) { + newParts[i] = partitions[i]; + } // for + trash = partitions; + partitions = newParts; + free(trash); + } // if + } else { // No existing partition table; just create it partitions = newParts; - free(trash); - } // if - } else { // No existing partition table; just create it - partitions = newParts; - } // if/else existing partitions - mainHeader.numParts = numEntries; - secondHeader.numParts = numEntries; - mainHeader.firstUsableLBA = ((numEntries * GPT_SIZE) / blockSize) + 2 ; - secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; - mainHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; - secondHeader.lastUsableLBA = mainHeader.lastUsableLBA; - secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); - if (diskSize > 0) - CheckGPTSize(); - } else { // Bad memory allocation - fprintf(stderr, "Error allocating memory for partition table!\n"); - allOK = 0; + } // if/else existing partitions + mainHeader.numParts = numEntries; + secondHeader.numParts = numEntries; + mainHeader.firstUsableLBA = ((numEntries * GPT_SIZE) / blockSize) + 2 ; + secondHeader.firstUsableLBA = mainHeader.firstUsableLBA; + MoveSecondHeaderToEnd(); + if (diskSize > 0) + CheckGPTSize(); + } else { // Bad memory allocation + fprintf(stderr, "Error allocating memory for partition table!\n"); + allOK = 0; + } // if/else } // if/else return (allOK); } // GPTData::SetGPTSize() @@ -1832,9 +1847,11 @@ int GPTData::ClearGPTData(void) { return (goOn); } // GPTData::ClearGPTData() -// Set the location of the second GPT header data to the correct location. -// Intended to help users of RAID arrays that have been resized. -void GPTData::FixSecondHeaderLocation() { +// Set the location of the second GPT header data to the end of the disk. +// Used internally and called by the 'e' option on the recovery & +// transformation menu, to help users of RAID arrays who add disk space +// to their arrays. +void GPTData::MoveSecondHeaderToEnd() { mainHeader.backupLBA = secondHeader.currentLBA = diskSize - UINT64_C(1); mainHeader.lastUsableLBA = secondHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA; secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); diff --git a/gpt.h b/gpt.h index c265169..f22bd61 100644 --- a/gpt.h +++ b/gpt.h @@ -127,7 +127,7 @@ public: void BlankPartitions(void); void SortGPT(void); int ClearGPTData(void); - void FixSecondHeaderLocation(); + void MoveSecondHeaderToEnd(); void SetName(uint32_t partNum, char* theName = NULL); void SetDiskGUID(GUIDData newGUID); int SetPartitionGUID(uint32_t pn, GUIDData theGUID); diff --git a/support.cc b/support.cc index 337dfce..bb419ed 100644 --- a/support.cc +++ b/support.cc @@ -480,6 +480,7 @@ uint64_t disksize(int fd, int *err) { sectors = bytes / UINT64_C(512); } // if } // if -// printf("In disksize(), sectors is %lld.\n", sectors); +// sectors = 25000000; +// printf("Returning bogus sector size: %d\n", sectors); return sectors; } -- GitLab