diff --git a/gpt.cc b/gpt.cc index 76cd9ad..375c216 100644 --- a/gpt.cc +++ b/gpt.cc @@ -1500,7 +1500,7 @@ int GPTData::DestroyGPT(void) { cerr << "Warning! GPT main partition table not overwritten! Error is " << errno << "\n"; allOK = 0; } // if write failed - } // if + } // if if (!myDisk.Seek(secondHeader.partitionEntriesLBA)) allOK = 0; if (allOK) { @@ -1911,6 +1911,23 @@ int GPTData::MoveMainTable(uint64_t pteSector) { return retval; } // GPTData::MoveMainTable() +// Change the start sector for the secondary partition table. +// Returns 1 on success, 0 on failure +int GPTData::MoveSecondaryTable(uint64_t pteSector) { + uint64_t pteSize = GetTableSizeInSectors(); + int retval = 1; + + if ((pteSector > FindLastUsedLBA()) && ((pteSector + pteSize) < diskSize)) { + secondHeader.partitionEntriesLBA = pteSector; // (RebuildSecondHeader actually replaces this with lastUsableLBA+1) + mainHeader.lastUsableLBA = secondHeader.partitionEntriesLBA - UINT64_C(1); + RebuildSecondHeader(); + } else { + cerr << "Unable to set the secondary partition table's location to " << pteSector << "!\n"; + retval = 0; + } // if/else + return retval; +} // GPTData::MoveSecondaryTable() + // Blank the partition array void GPTData::BlankPartitions(void) { uint32_t i; @@ -2285,7 +2302,7 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) { } // GPTData::FindFirstAvailable() // Returns the LBA of the start of the first partition on the disk (by -// sector number), or 0 if there are no partitions defined. +// sector number), or UINT64_MAX if there are no partitions defined. uint64_t GPTData::FindFirstUsedLBA(void) { uint32_t i; uint64_t firstFound = UINT64_MAX; @@ -2298,6 +2315,20 @@ uint64_t GPTData::FindFirstUsedLBA(void) { return firstFound; } // GPTData::FindFirstUsedLBA() +// Returns the LBA of the end of the last partition on the disk (by +// sector number), or 0 if there are no partitions defined. +uint64_t GPTData::FindLastUsedLBA(void) { + uint32_t i; + uint64_t lastFound = 0; + + for (i = 0; i < numParts; i++) { + if ((partitions[i].IsUsed()) && (partitions[i].GetFirstLBA() > lastFound)) { + lastFound = partitions[i].GetFirstLBA(); + } // if + } // for + return lastFound; +} // GPTData::FindLastUsedLBA() + // Finds the first available sector in the largest block of unallocated // space on the disk. Returns 0 if there are no available blocks left uint64_t GPTData::FindFirstInLargest(void) { diff --git a/gpt.h b/gpt.h index 5d19372..c272d65 100644 --- a/gpt.h +++ b/gpt.h @@ -142,6 +142,7 @@ public: // Adjust GPT structures WITHOUT user interaction... int SetGPTSize(uint32_t numEntries, int fillGPTSectors = 1); int MoveMainTable(uint64_t pteSector); + int MoveSecondaryTable(uint64_t pteSector); void BlankPartitions(void); int DeletePartition(uint32_t partNum); uint32_t CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector); @@ -158,7 +159,7 @@ public: void RecomputeCHS(void); int Align(uint64_t* sector); void SetProtectiveMBR(BasicMBRData & newMBR) {protectiveMBR = newMBR;} - + // Return data about the GPT structures.... WhichToUse GetState(void) {return whichWasUsed;} int GetPartRange(uint32_t* low, uint32_t* high); @@ -181,6 +182,7 @@ public: // Find information about free space uint64_t FindFirstAvailable(uint64_t start = 0); uint64_t FindFirstUsedLBA(void); + uint64_t FindLastUsedLBA(void); uint64_t FindFirstInLargest(void); uint64_t FindLastAvailable(); uint64_t FindLastInFree(uint64_t start, bool align = false); diff --git a/gptcl.cc b/gptcl.cc index 34c9421..f6517e4 100644 --- a/gptcl.cc +++ b/gptcl.cc @@ -68,7 +68,7 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) { int opt, numOptions = 0, saveData = 0, neverSaveData = 0; int partNum = 0, newPartNum = -1, saveNonGPT = 1, retval = 0, pretend = 0; int byteSwapPartNum = 0; - uint64_t low, high, startSector, endSector, sSize, mainTableLBA; + uint64_t low, high, startSector, endSector, sSize, mainTableLBA, secondTableLBA; uint64_t temp; // temporary variable; free to use in any case char *device; string cmd, typeGUID, name; @@ -94,7 +94,8 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) { {"hybrid", 'h', POPT_ARG_STRING, &hybrids, 'h', "create hybrid MBR", "partnum[:partnum...][:EE]"}, {"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"}, {"align-end", 'I', POPT_ARG_NONE, NULL, 'I', "align partition end points", ""}, - {"move-main-table", 'j', POPT_ARG_INT, &mainTableLBA, 'j', "adjust the location of the main partition table", "sector"}, + {"move-main-table", 'j', POPT_ARG_INT, &mainTableLBA, 'j', "change the start sector of the main partition table", "sector"}, + {"move-secondary-table", 'k', POPT_ARG_INT, &secondTableLBA, 'k', "change the start sector of the secondary partition table", "sector"}, {"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"}, {"list-types", 'L', POPT_ARG_NONE, NULL, 'L', "list known partition types", ""}, {"gpttombr", 'm', POPT_ARG_STRING, &mbrParts, 'm', "convert GPT to MBR", "partnum[:partnum...]"}, @@ -117,6 +118,7 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) { {"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT (but not MBR) data structures", ""}, {"zap-all", 'Z', POPT_ARG_NONE, NULL, 'Z', "zap (destroy) GPT and MBR data structures", ""}, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } + // TODO: Incorrect(ly documented) (long) arguments are silently swallowed and seem to take the next argument with them! }; // Create popt context... @@ -280,13 +282,21 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) { alignEnd = true; break; case 'j': - if (MoveMainTable(mainTableLBA)) { - JustLooking(0); - saveData = 1; - } else { - neverSaveData = 1; - } // if/else - break; + if (MoveMainTable(mainTableLBA)) { + JustLooking(0); + saveData = 1; + } else { + neverSaveData = 1; + } // if/else + break; + case 'k': + if (MoveSecondaryTable(secondTableLBA)) { + JustLooking(0); + saveData = 1; + } else { + neverSaveData = 1; + } // if/else + break; case 'l': LoadBackupFile(backupFile, saveData, neverSaveData); free(backupFile); diff --git a/sgdisk.8 b/sgdisk.8 index b966a13..dad877b 100644 --- a/sgdisk.8 +++ b/sgdisk.8 @@ -304,7 +304,7 @@ with the current final partition being aligned, and if \fBsgdisk\fR is asked to create a partition in that space, then it will \fBnot\fR be end\-aligned. .TP -.B \-j, \-\-adjust\-main\-table=sector +.B \-j, \-\-move\-main\-table=sector Adjust the location of the main partition table. This value is normally 2, but it may need to be increased in some cases, such as when a system\-on\-chip (SoC) is hard\-coded to read boot code from sector 2. I diff --git a/sgdisk.html b/sgdisk.html index 36a28bc..ec0f505 100644 --- a/sgdisk.html +++ b/sgdisk.html @@ -195,7 +195,7 @@ when using this option. The others require a partition number. The nand, xor, =, set, clear, and toggle options enable you to change the attribute bit value. The set, clear, toggle, and get options work on a -bit number; the others work on a hexadecimal bit mask. For example, type +bit number; the others work on a hexadecimal bit mask. For example, type sgdisk -A 4:set:2 /dev/sdc to set the bit 2 attribute (legacy BIOS bootable) on partition 4 on /dev/sdc.
@@ -344,7 +344,7 @@ if the free space at the end of a disk is less than the alignment value, with the current final partition being aligned, and if sgdisk is asked to create a partition in that space, then it will not be end-aligned.
-