Initial commit of support for moving main partition table to arbitrary
location on disk (within limits based on existing partitions).
This commit is contained in:
12
NEWS
12
NEWS
@@ -1,6 +1,16 @@
|
|||||||
1.0.2 (?/??/2016):
|
1.0.2 (?/??/2017):
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Added new option: 'j' on the experts' menu in gdisk;
|
||||||
|
'-j/--move-main-table={sector}' in sgdisk. This option enables relocating
|
||||||
|
the main partition table from sector 2 (the default location) to somewhere
|
||||||
|
else on the disk. The main reason I know of to do this is if the disk is
|
||||||
|
to be used with a system-on-chip (SoC) computer, some of which require the
|
||||||
|
boot loader to be located at sector 2. If you pass this option the default
|
||||||
|
value of 2, it has the effect of reducing the padding placed between the
|
||||||
|
main partition table and the first usable sector value created by the
|
||||||
|
Linux fdisk tool.
|
||||||
|
|
||||||
- Updated man pages with new recommendations for ESP and BIOS Boot Partition
|
- Updated man pages with new recommendations for ESP and BIOS Boot Partition
|
||||||
sizes.
|
sizes.
|
||||||
|
|
||||||
|
|||||||
8
gdisk.8
8
gdisk.8
@@ -466,6 +466,14 @@ boot.
|
|||||||
Show detailed partition information. This option is identical to the 'i'
|
Show detailed partition information. This option is identical to the 'i'
|
||||||
option on the main menu.
|
option on the main menu.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B j
|
||||||
|
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
|
||||||
|
recommend against adjusting this value unless doing so is absolutely
|
||||||
|
necessary.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B l
|
.B l
|
||||||
Change the sector alignment value. Disks with more logical sectors per
|
Change the sector alignment value. Disks with more logical sectors per
|
||||||
|
|||||||
56
gpt.cc
56
gpt.cc
@@ -276,6 +276,23 @@ int GPTData::Verify(void) {
|
|||||||
<< "The 'e' option on the experts' menu may fix this problem.\n";
|
<< "The 'e' option on the experts' menu may fix this problem.\n";
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
|
// Check the main and backup partition tables for overlap with things
|
||||||
|
if (mainHeader.partitionEntriesLBA + GetTableSizeInSectors() > mainHeader.firstUsableLBA) {
|
||||||
|
problems++;
|
||||||
|
cout << "\nProblem: Main partition table extends past the first usable LBA.\n"
|
||||||
|
<< "Using 'j' on the experts' menu may enable fixing this problem.\n";
|
||||||
|
} // if
|
||||||
|
if (mainHeader.partitionEntriesLBA < 2) {
|
||||||
|
problems++;
|
||||||
|
cout << "\nProblem: Main partition table appears impossibly early on the disk.\n"
|
||||||
|
<< "Using 'j' on the experts' menu may enable fixing this problem.\n";
|
||||||
|
} // if
|
||||||
|
if (secondHeader.partitionEntriesLBA + GetTableSizeInSectors() > secondHeader.currentLBA) {
|
||||||
|
problems++;
|
||||||
|
cout << "\nProblem: The backup partition table overlaps the backup header.\n"
|
||||||
|
<< "Using 'e' on the experts' menu may fix this problem.\n";
|
||||||
|
} // if
|
||||||
|
|
||||||
if ((mainHeader.lastUsableLBA >= diskSize) || (mainHeader.lastUsableLBA > mainHeader.backupLBA)) {
|
if ((mainHeader.lastUsableLBA >= diskSize) || (mainHeader.lastUsableLBA > mainHeader.backupLBA)) {
|
||||||
problems++;
|
problems++;
|
||||||
cout << "\nProblem: GPT claims the disk is larger than it is! (Claimed last usable\n"
|
cout << "\nProblem: GPT claims the disk is larger than it is! (Claimed last usable\n"
|
||||||
@@ -552,8 +569,8 @@ void GPTData::RebuildMainHeader(void) {
|
|||||||
mainHeader.firstUsableLBA = secondHeader.firstUsableLBA;
|
mainHeader.firstUsableLBA = secondHeader.firstUsableLBA;
|
||||||
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA;
|
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA;
|
||||||
mainHeader.diskGUID = secondHeader.diskGUID;
|
mainHeader.diskGUID = secondHeader.diskGUID;
|
||||||
mainHeader.partitionEntriesLBA = UINT64_C(2);
|
|
||||||
mainHeader.numParts = secondHeader.numParts;
|
mainHeader.numParts = secondHeader.numParts;
|
||||||
|
mainHeader.partitionEntriesLBA = secondHeader.firstUsableLBA - GetTableSizeInSectors();
|
||||||
mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries;
|
mainHeader.sizeOfPartitionEntries = secondHeader.sizeOfPartitionEntries;
|
||||||
mainHeader.partitionEntriesCRC = secondHeader.partitionEntriesCRC;
|
mainHeader.partitionEntriesCRC = secondHeader.partitionEntriesCRC;
|
||||||
memcpy(mainHeader.reserved2, secondHeader.reserved2, sizeof(mainHeader.reserved2));
|
memcpy(mainHeader.reserved2, secondHeader.reserved2, sizeof(mainHeader.reserved2));
|
||||||
@@ -658,7 +675,7 @@ int GPTData::FindInsanePartitions(void) {
|
|||||||
} // if
|
} // if
|
||||||
if (partitions[i].GetLastLBA() >= diskSize) {
|
if (partitions[i].GetLastLBA() >= diskSize) {
|
||||||
problems++;
|
problems++;
|
||||||
cout << "\nProblem: partition " << i + 1 << " is too big for the disk.\n";
|
cout << "\nProblem: partition " << i + 1 << " is too big for the disk.\n";
|
||||||
} // if
|
} // if
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
@@ -1441,6 +1458,8 @@ void GPTData::DisplayGPTData(void) {
|
|||||||
cout << "Logical sector size: " << blockSize << " bytes\n";
|
cout << "Logical sector size: " << blockSize << " bytes\n";
|
||||||
cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n";
|
cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n";
|
||||||
cout << "Partition table holds up to " << numParts << " entries\n";
|
cout << "Partition table holds up to " << numParts << " entries\n";
|
||||||
|
cout << "Main partition table begins at sector " << mainHeader.partitionEntriesLBA
|
||||||
|
<< " and ends at sector " << mainHeader.partitionEntriesLBA + GetTableSizeInSectors() - 1 << "\n";
|
||||||
cout << "First usable sector is " << mainHeader.firstUsableLBA
|
cout << "First usable sector is " << mainHeader.firstUsableLBA
|
||||||
<< ", last usable sector is " << mainHeader.lastUsableLBA << "\n";
|
<< ", last usable sector is " << mainHeader.lastUsableLBA << "\n";
|
||||||
totalFree = FindFreeBlocks(&i, &temp);
|
totalFree = FindFreeBlocks(&i, &temp);
|
||||||
@@ -1732,7 +1751,7 @@ int GPTData::SetGPTSize(uint32_t numEntries, int fillGPTSectors) {
|
|||||||
partitions = newParts;
|
partitions = newParts;
|
||||||
} // if/else existing partitions
|
} // if/else existing partitions
|
||||||
numParts = numEntries;
|
numParts = numEntries;
|
||||||
mainHeader.firstUsableLBA = ((numEntries * GPT_SIZE) / blockSize) + (((numEntries * GPT_SIZE) % blockSize) != 0) + 2 ;
|
mainHeader.firstUsableLBA = GetTableSizeInSectors() + mainHeader.partitionEntriesLBA;
|
||||||
secondHeader.firstUsableLBA = mainHeader.firstUsableLBA;
|
secondHeader.firstUsableLBA = mainHeader.firstUsableLBA;
|
||||||
MoveSecondHeaderToEnd();
|
MoveSecondHeaderToEnd();
|
||||||
if (diskSize > 0)
|
if (diskSize > 0)
|
||||||
@@ -1747,6 +1766,23 @@ int GPTData::SetGPTSize(uint32_t numEntries, int fillGPTSectors) {
|
|||||||
return (allOK);
|
return (allOK);
|
||||||
} // GPTData::SetGPTSize()
|
} // GPTData::SetGPTSize()
|
||||||
|
|
||||||
|
// Change the start sector for the main partition table.
|
||||||
|
// Returns 1 on success, 0 on failure
|
||||||
|
int GPTData::MoveMainTable(uint64_t pteSector) {
|
||||||
|
uint64_t pteSize = GetTableSizeInSectors();
|
||||||
|
int retval = 1;
|
||||||
|
|
||||||
|
if ((pteSector >= 2) && ((pteSector + pteSize) <= FindFirstUsedLBA())) {
|
||||||
|
mainHeader.partitionEntriesLBA = pteSector;
|
||||||
|
mainHeader.firstUsableLBA = pteSector + pteSize;
|
||||||
|
RebuildSecondHeader();
|
||||||
|
} else {
|
||||||
|
cerr << "Unable to set the main partition table's location to " << pteSector << "!\n";
|
||||||
|
retval = 0;
|
||||||
|
} // if/else
|
||||||
|
return retval;
|
||||||
|
} // GPTData::MoveMainTable()
|
||||||
|
|
||||||
// Blank the partition array
|
// Blank the partition array
|
||||||
void GPTData::BlankPartitions(void) {
|
void GPTData::BlankPartitions(void) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@@ -2121,6 +2157,20 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) {
|
|||||||
return (first);
|
return (first);
|
||||||
} // GPTData::FindFirstAvailable()
|
} // 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.
|
||||||
|
uint64_t GPTData::FindFirstUsedLBA(void) {
|
||||||
|
uint32_t i;
|
||||||
|
uint64_t firstFound = UINT64_MAX;
|
||||||
|
|
||||||
|
for (i = 0; i < numParts; i++) {
|
||||||
|
if ((partitions[i].IsUsed()) && (partitions[i].GetFirstLBA() < firstFound)) {
|
||||||
|
firstFound = partitions[i].GetFirstLBA();
|
||||||
|
} // if
|
||||||
|
} // for
|
||||||
|
return firstFound;
|
||||||
|
} // GPTData::FindFirstUsedLBA()
|
||||||
|
|
||||||
// Finds the first available sector in the largest block of unallocated
|
// Finds the first available sector in the largest block of unallocated
|
||||||
// space on the disk. Returns 0 if there are no available blocks left
|
// space on the disk. Returns 0 if there are no available blocks left
|
||||||
uint64_t GPTData::FindFirstInLargest(void) {
|
uint64_t GPTData::FindFirstInLargest(void) {
|
||||||
|
|||||||
4
gpt.h
4
gpt.h
@@ -140,6 +140,7 @@ public:
|
|||||||
|
|
||||||
// Adjust GPT structures WITHOUT user interaction...
|
// Adjust GPT structures WITHOUT user interaction...
|
||||||
int SetGPTSize(uint32_t numEntries, int fillGPTSectors = 1);
|
int SetGPTSize(uint32_t numEntries, int fillGPTSectors = 1);
|
||||||
|
int MoveMainTable(uint64_t pteSector);
|
||||||
void BlankPartitions(void);
|
void BlankPartitions(void);
|
||||||
int DeletePartition(uint32_t partNum);
|
int DeletePartition(uint32_t partNum);
|
||||||
uint32_t CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector);
|
uint32_t CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector);
|
||||||
@@ -162,6 +163,8 @@ public:
|
|||||||
int GetPartRange(uint32_t* low, uint32_t* high);
|
int GetPartRange(uint32_t* low, uint32_t* high);
|
||||||
int FindFirstFreePart(void);
|
int FindFirstFreePart(void);
|
||||||
uint32_t GetNumParts(void) {return mainHeader.numParts;}
|
uint32_t GetNumParts(void) {return mainHeader.numParts;}
|
||||||
|
uint64_t GetTableSizeInSectors(void) {return (((numParts * GPT_SIZE) / blockSize) +
|
||||||
|
(((numParts * GPT_SIZE) % blockSize) != 0)); }
|
||||||
uint64_t GetMainHeaderLBA(void) {return mainHeader.currentLBA;}
|
uint64_t GetMainHeaderLBA(void) {return mainHeader.currentLBA;}
|
||||||
uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}
|
uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}
|
||||||
uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
|
uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
|
||||||
@@ -176,6 +179,7 @@ public:
|
|||||||
|
|
||||||
// Find information about free space
|
// Find information about free space
|
||||||
uint64_t FindFirstAvailable(uint64_t start = 0);
|
uint64_t FindFirstAvailable(uint64_t start = 0);
|
||||||
|
uint64_t FindFirstUsedLBA(void);
|
||||||
uint64_t FindFirstInLargest(void);
|
uint64_t FindFirstInLargest(void);
|
||||||
uint64_t FindLastAvailable();
|
uint64_t FindLastAvailable();
|
||||||
uint64_t FindLastInFree(uint64_t start);
|
uint64_t FindLastInFree(uint64_t start);
|
||||||
|
|||||||
11
gptcl.cc
11
gptcl.cc
@@ -64,7 +64,7 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
|
|||||||
GPTData secondDevice;
|
GPTData secondDevice;
|
||||||
int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
|
int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
|
||||||
int partNum = 0, newPartNum = -1, saveNonGPT = 1, retval = 0, pretend = 0;
|
int partNum = 0, newPartNum = -1, saveNonGPT = 1, retval = 0, pretend = 0;
|
||||||
uint64_t low, high, startSector, endSector, sSize;
|
uint64_t low, high, startSector, endSector, sSize, mainTableLBA;
|
||||||
uint64_t temp; // temporary variable; free to use in any case
|
uint64_t temp; // temporary variable; free to use in any case
|
||||||
char *device;
|
char *device;
|
||||||
string cmd, typeGUID, name;
|
string cmd, typeGUID, name;
|
||||||
@@ -88,6 +88,7 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
|
|||||||
{"randomize-guids", 'G', POPT_ARG_NONE, NULL, 'G', "randomize disk and partition GUIDs", ""},
|
{"randomize-guids", 'G', POPT_ARG_NONE, NULL, 'G', "randomize disk and partition GUIDs", ""},
|
||||||
{"hybrid", 'h', POPT_ARG_STRING, &hybrids, 'h', "create hybrid MBR", "partnum[:partnum...]"},
|
{"hybrid", 'h', POPT_ARG_STRING, &hybrids, 'h', "create hybrid MBR", "partnum[:partnum...]"},
|
||||||
{"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
|
{"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
|
||||||
|
{"move-main-table", 'j', POPT_ARG_INT, &mainTableLBA, 'j', "adjust the location of the main partition table", "sector"},
|
||||||
{"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"},
|
{"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", ""},
|
{"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...]"},
|
{"gpttombr", 'm', POPT_ARG_STRING, &mbrParts, 'm', "convert GPT to MBR", "partnum[:partnum...]"},
|
||||||
@@ -262,6 +263,14 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
|
|||||||
case 'i':
|
case 'i':
|
||||||
ShowPartDetails(infoPartNum - 1);
|
ShowPartDetails(infoPartNum - 1);
|
||||||
break;
|
break;
|
||||||
|
case 'j':
|
||||||
|
if (MoveMainTable(mainTableLBA)) {
|
||||||
|
JustLooking(0);
|
||||||
|
saveData = 1;
|
||||||
|
} else {
|
||||||
|
neverSaveData = 1;
|
||||||
|
} // if/else
|
||||||
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
LoadBackupFile(backupFile, saveData, neverSaveData);
|
LoadBackupFile(backupFile, saveData, neverSaveData);
|
||||||
free(backupFile);
|
free(backupFile);
|
||||||
|
|||||||
25
gpttext.cc
25
gpttext.cc
@@ -132,7 +132,7 @@ int GPTDataTextUI::XFormDisklabel(void) {
|
|||||||
numDone = GPTData::XFormDisklabel(partNum);
|
numDone = GPTData::XFormDisklabel(partNum);
|
||||||
|
|
||||||
return numDone;
|
return numDone;
|
||||||
} // GPTData::XFormDisklabel(void)
|
} // GPTDataTextUI::XFormDisklabel(void)
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
@@ -179,6 +179,24 @@ void GPTDataTextUI::ResizePartitionTable(void) {
|
|||||||
SetGPTSize(newSize);
|
SetGPTSize(newSize);
|
||||||
} // GPTDataTextUI::ResizePartitionTable()
|
} // GPTDataTextUI::ResizePartitionTable()
|
||||||
|
|
||||||
|
// Move the main partition table (to enable some SoC boot loaders to place
|
||||||
|
// code at sector 2, for instance).
|
||||||
|
void GPTDataTextUI::MoveMainTable(void) {
|
||||||
|
uint64_t newStart, pteSize = GetTableSizeInSectors();
|
||||||
|
uint64_t maxValue = FindFirstUsedLBA() - pteSize;
|
||||||
|
ostringstream prompt;
|
||||||
|
|
||||||
|
cout << "Currently, main partition table begins at sector " << mainHeader.partitionEntriesLBA
|
||||||
|
<< " and ends at sector " << mainHeader.partitionEntriesLBA + pteSize - 1 << "\n";
|
||||||
|
prompt << "Enter new starting location (2 to " << maxValue << "; default is 2; 1 to abort): ";
|
||||||
|
newStart = GetNumber(1, maxValue, 2, prompt.str());
|
||||||
|
if (newStart != 1) {
|
||||||
|
GPTData::MoveMainTable(newStart);
|
||||||
|
} else {
|
||||||
|
cout << "Aborting change!\n";
|
||||||
|
} // if
|
||||||
|
} // GPTDataTextUI::MoveMainTable()
|
||||||
|
|
||||||
// Interactively create a partition
|
// Interactively create a partition
|
||||||
void GPTDataTextUI::CreatePartition(void) {
|
void GPTDataTextUI::CreatePartition(void) {
|
||||||
uint64_t firstBlock, firstInLargest, lastBlock, sector, origSector;
|
uint64_t firstBlock, firstInLargest, lastBlock, sector, origSector;
|
||||||
@@ -811,6 +829,9 @@ void GPTDataTextUI::ExpertsMenu(string filename) {
|
|||||||
case 'i': case 'I':
|
case 'i': case 'I':
|
||||||
ShowDetails();
|
ShowDetails();
|
||||||
break;
|
break;
|
||||||
|
case 'j': case 'J':
|
||||||
|
MoveMainTable();
|
||||||
|
break;
|
||||||
case 'l': case 'L':
|
case 'l': case 'L':
|
||||||
prompt.seekp(0);
|
prompt.seekp(0);
|
||||||
prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = "
|
prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = "
|
||||||
@@ -878,9 +899,11 @@ void GPTDataTextUI::ShowExpertCommands(void) {
|
|||||||
cout << "c\tchange partition GUID\n";
|
cout << "c\tchange partition GUID\n";
|
||||||
cout << "d\tdisplay the sector alignment value\n";
|
cout << "d\tdisplay the sector alignment value\n";
|
||||||
cout << "e\trelocate backup data structures to the end of the disk\n";
|
cout << "e\trelocate backup data structures to the end of the disk\n";
|
||||||
|
cout << "f\trandomize disk and partition unique GUIDs\n";
|
||||||
cout << "g\tchange disk GUID\n";
|
cout << "g\tchange disk GUID\n";
|
||||||
cout << "h\trecompute CHS values in protective/hybrid MBR\n";
|
cout << "h\trecompute CHS values in protective/hybrid MBR\n";
|
||||||
cout << "i\tshow detailed information on a partition\n";
|
cout << "i\tshow detailed information on a partition\n";
|
||||||
|
cout << "j\tmove the main partition table\n";
|
||||||
cout << "l\tset the sector alignment value\n";
|
cout << "l\tset the sector alignment value\n";
|
||||||
cout << "m\treturn to main menu\n";
|
cout << "m\treturn to main menu\n";
|
||||||
cout << "n\tcreate a new protective MBR\n";
|
cout << "n\tcreate a new protective MBR\n";
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class GPTDataTextUI : public GPTData {
|
|||||||
// Request information from the user (& possibly do something with it)
|
// Request information from the user (& possibly do something with it)
|
||||||
uint32_t GetPartNum(void);
|
uint32_t GetPartNum(void);
|
||||||
void ResizePartitionTable(void);
|
void ResizePartitionTable(void);
|
||||||
|
void MoveMainTable(void);
|
||||||
void CreatePartition(void);
|
void CreatePartition(void);
|
||||||
void DeletePartition(void);
|
void DeletePartition(void);
|
||||||
void ChangePartType(void);
|
void ChangePartType(void);
|
||||||
|
|||||||
8
sgdisk.8
8
sgdisk.8
@@ -280,6 +280,14 @@ unique GUID and the translation of \fBsgdisk\fR's
|
|||||||
internal partition type code to a plain type name. The \fI\-i\fR option
|
internal partition type code to a plain type name. The \fI\-i\fR option
|
||||||
displays this information for a single partition.
|
displays this information for a single partition.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B \-j, \-\-adjust\-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
|
||||||
|
recommend against adjusting this value unless doing so is absolutely
|
||||||
|
necessary.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-l, \-\-load\-backup=file
|
.B \-l, \-\-load\-backup=file
|
||||||
Load partition data from a backup file. This option is the reverse of the
|
Load partition data from a backup file. This option is the reverse of the
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ string ReadString(void) {
|
|||||||
// If user provides no input, def (default value) is returned.
|
// If user provides no input, def (default value) is returned.
|
||||||
// (If def is outside of the low-high range, an explicit response
|
// (If def is outside of the low-high range, an explicit response
|
||||||
// is required.)
|
// is required.)
|
||||||
int GetNumber(int low, int high, int def, const string & prompt) {
|
uint64_t GetNumber(uint64_t low, uint64_t high, uint64_t def, const string & prompt) {
|
||||||
int response, num;
|
uint64_t response, num;
|
||||||
char line[255];
|
char line[255];
|
||||||
|
|
||||||
if (low != high) { // bother only if low and high differ...
|
if (low != high) { // bother only if low and high differ...
|
||||||
@@ -77,7 +77,7 @@ int GetNumber(int low, int high, int def, const string & prompt) {
|
|||||||
cin.getline(line, 255);
|
cin.getline(line, 255);
|
||||||
if (!cin.good())
|
if (!cin.good())
|
||||||
exit(5);
|
exit(5);
|
||||||
num = sscanf(line, "%d", &response);
|
num = sscanf(line, "%ld", &response);
|
||||||
if (num == 1) { // user provided a response
|
if (num == 1) { // user provided a response
|
||||||
if ((response < low) || (response > high))
|
if ((response < low) || (response > high))
|
||||||
cout << "Value out of range\n";
|
cout << "Value out of range\n";
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
string ReadString(void);
|
string ReadString(void);
|
||||||
int GetNumber(int low, int high, int def, const string & prompt);
|
uint64_t GetNumber(uint64_t low, uint64_t high, uint64_t def, const string & prompt);
|
||||||
char GetYN(void);
|
char GetYN(void);
|
||||||
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
|
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
|
||||||
uint64_t IeeeToInt(string IeeeValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def = 0);
|
uint64_t IeeeToInt(string IeeeValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def = 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user