nixos-installer/patches/gptfdisk-move-secondary-table.patch
2023-01-03 18:50:07 +01:00

386 lines
17 KiB
Diff

diff --git a/gpt.cc b/gpt.cc
index 76cd9ad..4798db2 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::MoveSecondTable(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::MoveSecondTable()
+
// Blank the partition array
void GPTData::BlankPartitions(void) {
uint32_t i;
@@ -2066,6 +2083,7 @@ void GPTData::MoveSecondHeaderToEnd() {
} // if
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA;
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
+ // TODO: Whenever this gets called, it moves the backup table to be the same distance from the backup header as the primary one it from its header. This seems highly problematic, since MoveMainTable does not call this, but then further actions may or may not do so. Moving the primary table may thus imply moving the backup table, or it may leave it where it was. There is also no guarantee that the space where the backup table is moved to is actually available.
} // GPTData::FixSecondHeaderLocation()
// Sets the partition's name to the specified UnicodeString without
@@ -2285,7 +2303,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 +2316,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..17b3380 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 MoveSecondTable(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..f4361b7 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;
@@ -85,7 +85,7 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
{"recompute-chs", 'C', POPT_ARG_NONE, NULL, 'C', "recompute CHS values in protective/hybrid MBR", ""},
{"delete", 'd', POPT_ARG_INT, &deletePartNum, 'd', "delete a partition", "partnum"},
{"display-alignment", 'D', POPT_ARG_NONE, NULL, 'D', "show number of sectors per allocation block", ""},
- {"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second header to end of disk", ""},
+ {"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second/backup header to end of disk", ""},
{"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
{"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
{"first-aligned-in-largest", 'F', POPT_ARG_NONE, NULL, 'F', "show start of the largest free block, aligned", ""},
@@ -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-backup-table", 'k', POPT_ARG_INT, &secondTableLBA, 'k', "change the start sector of the second/backup 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...
@@ -156,12 +158,12 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
// Assume first non-option argument is the device filename....
device = (char*) poptGetArg(poptCon);
- poptResetContext(poptCon);
if (device != NULL) {
JustLooking(); // reset as necessary
BeQuiet(); // Tell called functions to be less verbose & interactive
if (LoadPartitions((string) device)) {
+ device = NULL; poptResetContext(poptCon);
if ((WhichWasUsed() == use_mbr) || (WhichWasUsed() == use_bsd))
saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
sSize = GetBlockSize();
@@ -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 (MoveSecondTable(secondTableLBA)) {
+ JustLooking(0);
+ saveData = 1;
+ } else {
+ neverSaveData = 1;
+ } // if/else
+ break;
case 'l':
LoadBackupFile(backupFile, saveData, neverSaveData);
free(backupFile);
diff --git a/gpttext.cc b/gpttext.cc
index 170a169..43be9e5 100644
--- a/gpttext.cc
+++ b/gpttext.cc
@@ -197,6 +197,24 @@ void GPTDataTextUI::MoveMainTable(void) {
} // if
} // GPTDataTextUI::MoveMainTable()
+// Move the backup partition table.
+void GPTDataTextUI::MoveSecondTable(void) {
+ uint64_t newStart, pteSize = GetTableSizeInSectors();
+ uint64_t minValue = FindLastUsedLBA();
+ uint64_t maxValue = diskSize - 1 - pteSize;
+ ostringstream prompt;
+
+ cout << "Currently, backup partition table begins at sector " << secondHeader.partitionEntriesLBA
+ << " and ends at sector " << secondHeader.partitionEntriesLBA + pteSize - 1 << "\n";
+ prompt << "Enter new starting location (" << minValue << " to " << maxValue << "; default is " << minValue << "; 1 to abort): ";
+ newStart = GetNumber(1, maxValue, minValue, prompt.str());
+ if (newStart != 1) {
+ GPTData::MoveSecondTable(newStart);
+ } else {
+ cout << "Aborting change!\n";
+ } // if
+} // GPTDataTextUI::MoveSecondTable()
+
// Interactively create a partition
void GPTDataTextUI::CreatePartition(void) {
uint64_t firstBlock, firstInLargest, lastBlock, sector, origSector, lastAligned;
@@ -698,7 +716,7 @@ void GPTDataTextUI::ShowCommands(void) {
void GPTDataTextUI::RecoveryMenu(string filename) {
uint32_t numParts;
int goOn = 1, temp1;
-
+
do {
cout << "\nRecovery/transformation command (? for help): ";
switch (ReadString()[0]) {
@@ -824,7 +842,7 @@ void GPTDataTextUI::ExpertsMenu(string filename) {
string guidStr, device;
GUIDData aGUID;
ostringstream prompt;
-
+
do {
cout << "\nExpert command (? for help): ";
switch (ReadString()[0]) {
@@ -873,6 +891,9 @@ void GPTDataTextUI::ExpertsMenu(string filename) {
case 'j': case 'J':
MoveMainTable();
break;
+ case 'k': case 'K':
+ MoveSecondTable();
+ break;
case 'l': case 'L':
prompt.seekp(0);
prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = "
@@ -946,6 +967,7 @@ void GPTDataTextUI::ShowExpertCommands(void) {
cout << "h\trecompute CHS values in protective/hybrid MBR\n";
cout << "i\tshow detailed information on a partition\n";
cout << "j\tmove the main partition table\n";
+ cout << "k\tmove the backup partition table\n";
cout << "l\tset the sector alignment value\n";
cout << "m\treturn to main menu\n";
cout << "n\tcreate a new protective MBR\n";
@@ -1007,4 +1029,4 @@ UnicodeString ReadUString(void) {
return ReadString().c_str();
} // ReadUString()
#endif
-
+
diff --git a/gpttext.h b/gpttext.h
index 32e2f88..8ed6274 100644
--- a/gpttext.h
+++ b/gpttext.h
@@ -41,6 +41,7 @@ class GPTDataTextUI : public GPTData {
uint32_t GetPartNum(void);
void ResizePartitionTable(void);
void MoveMainTable(void);
+ void MoveSecondTable(void);
void CreatePartition(void);
void DeletePartition(void);
void ChangePartType(void);
diff --git a/guid.cc b/guid.cc
index 1e73ab7..387019a 100644
--- a/guid.cc
+++ b/guid.cc
@@ -139,29 +139,28 @@ void GUIDData::Zero(void) {
// (immediately after creating the UUID on Windows 7 being an important
// exception).
void GUIDData::Randomize(void) {
- int i, uuidGenerated = 0;
-#ifdef _UUID_UUID_H
+#ifndef _WIN32
uuid_generate(uuidData);
ReverseBytes(&uuidData[0], 4);
ReverseBytes(&uuidData[4], 2);
ReverseBytes(&uuidData[6], 2);
- uuidGenerated = 1;
-#endif
+#else
+
#if defined (_RPC_H) || defined (__RPC_H__)
UUID MsUuid;
if (UuidCreate(&MsUuid) == RPC_S_OK) {
memcpy(uuidData, &MsUuid, 16);
uuidGenerated = 1;
} // if
+#else
+ cerr << "Warning! Unable to generate a proper UUID! Creating an improper one as a last\n"
+ << "resort! Windows 7 may crash if you save this partition table!\a\n";
+ for (int i = 0; i < 16; i++)
+ uuidData[i] = (unsigned char) (256.0 * (rand() / (RAND_MAX + 1.0)));
+#endif
#endif
- if (!uuidGenerated) {
- cerr << "Warning! Unable to generate a proper UUID! Creating an improper one as a last\n"
- << "resort! Windows 7 may crash if you save this partition table!\a\n";
- for (i = 0; i < 16; i++)
- uuidData[i] = (unsigned char) (256.0 * (rand() / (RAND_MAX + 1.0)));
- } // if
} // GUIDData::Randomize
// Equality operator; returns 1 if the GUIDs are equal, 0 if they're unequal
diff --git a/sgdisk.8 b/sgdisk.8
index b966a13..6f8b375 100644
--- a/sgdisk.8
+++ b/sgdisk.8
@@ -304,13 +304,23 @@ 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
-Adjust the location of the main partition table. This value is normally 2,
+.B \-j, \-\-move\-main\-table=sector
+Sets the start sector 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
recommend against adjusting this value unless doing so is absolutely
necessary.
+.TP
+.B \-k, \-\-move\-backup\-table=sector
+Sets the start sector of the second/backup partition table. The backup table
+is usually placed just before the last sector, which holds the backup header.
+The default value is thus the size of the disk, minus one, minus the total
+size of the partition table (in sectors, usually 32).
+There are probably very few reasons to ever change this, and while the EFI
+standard does not mandate it, most tooling assumes the backup table to be at
+the very end of the disk.
+
.TP
.B \-l, \-\-load\-backup=file
Load partition data from a backup file. This option is the reverse of the
diff --git a/sgdisk.html b/sgdisk.html
index 36a28bc..98c20be 100644
--- a/sgdisk.html
+++ b/sgdisk.html
@@ -195,7 +195,7 @@ when using this option. The others require a partition number. The
<I>nand</I>, <I>xor</I>, <I>=</I>, <I>set</I>, <I>clear</I>, and
<I>toggle</I> options enable you to change the attribute bit value. The
<I>set</I>, <I>clear</I>, <I>toggle</I>, and <I>get</I> 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
<B>sgdisk -A 4:set:2 /dev/sdc</B> to set the bit 2 attribute (legacy BIOS
bootable) on partition 4 on <I>/dev/sdc</I>.
<P>
@@ -344,15 +344,26 @@ 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 <B>sgdisk</B> is asked
to create a partition in that space, then it will <B>not</B> be end-aligned.
<P>
-<DT><B>-j, --adjust-main-table=sector</B>
+<DT><B>-j, --move-main-table=sector</B>
<DD>
-Adjust the location of the main partition table. This value is normally 2,
+Sets the start sector 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
recommend against adjusting this value unless doing so is absolutely
necessary.
<P>
+<DT><B>-k, --move-backup-table=sector</B>
+
+<DD>
+Sets the start sector of the second/backup partition table. The backup table
+is usually placed just before the last sector, which holds the backup header.
+The default value is thus the size of the disk, minus one, minus the total
+size of the partition table (in sectors, usually 32).
+There are probably very few reasons to ever change this, and while the EFI
+standard does not mandate it, most tooling assumes the backup table to be at
+the very end of the disk.
+<P>
<DT><B>-l, --load-backup=file</B>
<DD>