forked from NiklasGollenstede/nixos-installer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gptfdisk-move-secondary-table.patch
385 lines (370 loc) · 16.8 KB
/
gptfdisk-move-secondary-table.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
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>