Add end-alignment feature.

This commit is contained in:
Rod Smith
2022-01-29 10:51:02 -05:00
parent 43b3df969c
commit fd60f74362
13 changed files with 141 additions and 74 deletions

10
NEWS
View File

@@ -1,9 +1,17 @@
1.0.9 (?/?/2021): 1.0.9 (?/?/2022):
----------------- -----------------
- Removed stray debugging code that caused "partNum is {x}" to be printed - Removed stray debugging code that caused "partNum is {x}" to be printed
when changing a partition's name with sgdisk (-c/--change-name). when changing a partition's name with sgdisk (-c/--change-name).
- Added support for aligning partitions' end points, as well as their start
points. This support affects the default partition size when using 'n' in
gdisk; it affects the default partition size in cgdisk; and it's activated
by the new '-I' option in sgdisk. See the programs' respective man pages
for details. This feature is intended to help with LUKS2 encryption, which
reacts badly to partitions that are not sized as exact multiples of the
encryption block size.
1.0.8 (6/9/2021): 1.0.8 (6/9/2021):
----------------- -----------------

View File

@@ -186,8 +186,13 @@ new disks, GPT fdisk attempts to align partitions on 1 MiB boundaries
performance for all of these disk types. On pre\-partitioned disks, GPT performance for all of these disk types. On pre\-partitioned disks, GPT
fdisk attempts to identify the alignment value used on that disk, but will fdisk attempts to identify the alignment value used on that disk, but will
set 8-sector alignment on disks larger than 300 GB even if lesser alignment set 8-sector alignment on disks larger than 300 GB even if lesser alignment
values are detected. In either case, it can be changed by using this values are detected. In either case, it can be changed by using this option.
option. The alignment value also affects the default end sector value when creating
a new partition; it will be aligned to one less than a multiple of the
alignment value, when possible. This should keep partitions a multiple of
the alignment value in size. Some disk encryption tools require partitions
to be sized to some value, typically 4096 bytes, so the default alignment of
1 MiB works well for them.
.TP .TP
.B Backup .B Backup

16
gdisk.8
View File

@@ -210,7 +210,8 @@ default start sector, or \fI\fB\-200M\fR\fR to specify a point 200MiB
before the last available sector. Pressing the Enter key with no input before the last available sector. Pressing the Enter key with no input
specifies the default value, which is the start of the largest available specifies the default value, which is the start of the largest available
block for the start sector and the end of the same block for the end block for the start sector and the end of the same block for the end
sector. sector. Default start and end points may be adjusted to optimize partition
alignment.
.TP .TP
.B o .B o
@@ -491,13 +492,18 @@ Change the sector alignment value. Disks with more logical sectors per
physical sectors (such as modern Advanced Format drives), some RAID physical sectors (such as modern Advanced Format drives), some RAID
configurations, and many SSD devices, can suffer performance problems if configurations, and many SSD devices, can suffer performance problems if
partitions are not aligned properly for their internal data structures. On partitions are not aligned properly for their internal data structures. On
new disks, GPT fdisk attempts to align partitions on 1 MiB boundaries new disks, GPT fdisk attempts to align partitions on 1 MiB boundaries (2048
(2048\-sectors on disks with 512-byte sectors) by default, which optimizes sectors on disks with 512-byte sectors) by default, which optimizes
performance for all of these disk types. On pre\-partitioned disks, GPT performance for all of these disk types. On pre\-partitioned disks, GPT
fdisk attempts to identify the alignment value used on that disk, but will fdisk attempts to identify the alignment value used on that disk, but will
set 8-sector alignment on disks larger than 300 GB even if lesser alignment set 8-sector alignment on disks larger than 300 GB even if lesser alignment
values are detected. In either case, it can be changed by using this values are detected. In either case, it can be changed by using this option.
option. The alignment value also affects the default end sector value when creating
a new partition; it will be aligned to one less than a multiple of the
alignment value, if possible. This should keep partitions a multiple of the
alignment value in size. Some disk encryption tools require partitions to be
sized to some value, typically 4096 bytes, so the default alignment of 1 MiB
works well for them.
.TP .TP
.B m .B m

34
gpt.cc
View File

@@ -3,7 +3,7 @@
/* By Rod Smith, initial coding January to February, 2009 */ /* By Rod Smith, initial coding January to February, 2009 */
/* This program is copyright (c) 2009-2018 by Roderick W. Smith. It is distributed /* This program is copyright (c) 2009-2022 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
@@ -410,6 +410,11 @@ int GPTData::Verify(void) {
<< "in degraded performance on some modern (2009 and later) hard disks.\n"; << "in degraded performance on some modern (2009 and later) hard disks.\n";
alignProbs++; alignProbs++;
} // if } // if
if ((partitions[i].IsUsed()) && ((partitions[i].GetLastLBA() + 1) % testAlignment) != 0) {
cout << "\nCaution: Partition " << i + 1 << " doesn't end on a "
<< testAlignment << "-sector boundary. This may\nresult "
<< "in problems with some disk encryption tools.\n";
} // if
} // for } // for
if (alignProbs > 0) if (alignProbs > 0)
cout << "\nConsult http://www.ibm.com/developerworks/linux/library/l-4kb-sector-disks/\n" cout << "\nConsult http://www.ibm.com/developerworks/linux/library/l-4kb-sector-disks/\n"
@@ -2334,18 +2339,28 @@ uint64_t GPTData::FindLastAvailable(void) {
} // GPTData::FindLastAvailable() } // GPTData::FindLastAvailable()
// Find the last available block in the free space pointed to by start. // Find the last available block in the free space pointed to by start.
uint64_t GPTData::FindLastInFree(uint64_t start) { // If align == true, returns the last sector that's aligned on the
uint64_t nearestStart; // system alignment value (unless that's less than the start value);
// if align == false, returns the last available block regardless of
// alignment. (The align variable is set to false by default.)
uint64_t GPTData::FindLastInFree(uint64_t start, bool align) {
uint64_t nearestEnd, endPlus;
uint32_t i; uint32_t i;
nearestStart = mainHeader.lastUsableLBA; nearestEnd = mainHeader.lastUsableLBA;
for (i = 0; i < numParts; i++) { for (i = 0; i < numParts; i++) {
if ((nearestStart > partitions[i].GetFirstLBA()) && if ((nearestEnd > partitions[i].GetFirstLBA()) &&
(partitions[i].GetFirstLBA() > start)) { (partitions[i].GetFirstLBA() > start)) {
nearestStart = partitions[i].GetFirstLBA() - 1; nearestEnd = partitions[i].GetFirstLBA() - 1;
} // if } // if
} // for } // for
return (nearestStart); if (align) {
endPlus = nearestEnd + 1;
if (Align(&endPlus) && IsFree(endPlus - 1) && (endPlus > start)) {
nearestEnd = endPlus - 1;
} // if
} // if
return (nearestEnd);
} // GPTData::FindLastInFree() } // GPTData::FindLastInFree()
// Finds the total number of free blocks, the number of segments in which // Finds the total number of free blocks, the number of segments in which
@@ -2422,7 +2437,10 @@ int GPTData::IsUsedPartNum(uint32_t partNum) {
***********************************************************/ ***********************************************************/
// Set partition alignment value; partitions will begin on multiples of // Set partition alignment value; partitions will begin on multiples of
// the specified value // the specified value, and the default end values will be set so that
// partition sizes are multiples of this value in cgdisk and gdisk, too.
// (In sgdisk, end-alignment is done only if the '-I' command-line option
// is used.)
void GPTData::SetAlignment(uint32_t n) { void GPTData::SetAlignment(uint32_t n) {
if (n > 0) { if (n > 0) {
sectorAlignment = n; sectorAlignment = n;

4
gpt.h
View File

@@ -1,7 +1,7 @@
/* gpt.h -- GPT and data structure definitions, types, and /* gpt.h -- GPT and data structure definitions, types, and
functions */ functions */
/* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed /* This program is copyright (c) 2009-2022 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#ifndef __GPTSTRUCTS #ifndef __GPTSTRUCTS
@@ -185,7 +185,7 @@ public:
uint64_t FindFirstUsedLBA(void); 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, bool align = false);
uint64_t FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment); uint64_t FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment);
int IsFree(uint64_t sector, uint32_t *partNum = NULL); int IsFree(uint64_t sector, uint32_t *partNum = NULL);
int IsFreePartNum(uint32_t partNum); int IsFreePartNum(uint32_t partNum);

View File

@@ -1,7 +1,7 @@
/* /*
Implementation of GPTData class derivative with popt-based command Implementation of GPTData class derivative with popt-based command
line processing line processing
Copyright (C) 2010-2014 Roderick W. Smith Copyright (C) 2010-2022 Roderick W. Smith
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -30,6 +30,7 @@ GPTDataCL::GPTDataCL(void) {
attributeOperation = backupFile = partName = hybrids = newPartInfo = NULL; attributeOperation = backupFile = partName = hybrids = newPartInfo = NULL;
mbrParts = twoParts = outDevice = typeCode = partGUID = diskGUID = NULL; mbrParts = twoParts = outDevice = typeCode = partGUID = diskGUID = NULL;
alignment = DEFAULT_ALIGNMENT; alignment = DEFAULT_ALIGNMENT;
alignEnd = false;
deletePartNum = infoPartNum = largestPartNum = bsdPartNum = 0; deletePartNum = infoPartNum = largestPartNum = bsdPartNum = 0;
tableSize = GPT_SIZE; tableSize = GPT_SIZE;
} // GPTDataCL constructor } // GPTDataCL constructor
@@ -90,6 +91,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...][:EE]"}, {"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"}, {"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', "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", ""},
@@ -272,6 +274,9 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
case 'i': case 'i':
ShowPartDetails(infoPartNum - 1); ShowPartDetails(infoPartNum - 1);
break; break;
case 'I':
alignEnd = true;
break;
case 'j': case 'j':
if (MoveMainTable(mainTableLBA)) { if (MoveMainTable(mainTableLBA)) {
JustLooking(0); JustLooking(0);
@@ -307,9 +312,9 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
newPartNum = FindFirstFreePart(); newPartNum = FindFirstFreePart();
low = FindFirstInLargest(); low = FindFirstInLargest();
Align(&low); Align(&low);
high = FindLastInFree(low); high = FindLastInFree(low, alignEnd);
startSector = IeeeToInt(GetString(newPartInfo, 2), sSize, low, high, low); startSector = IeeeToInt(GetString(newPartInfo, 2), sSize, low, high, sectorAlignment, low);
endSector = IeeeToInt(GetString(newPartInfo, 3), sSize, startSector, high, high); endSector = IeeeToInt(GetString(newPartInfo, 3), sSize, startSector, high, sectorAlignment, high);
if (CreatePartition(newPartNum, startSector, endSector)) { if (CreatePartition(newPartNum, startSector, endSector)) {
saveData = 1; saveData = 1;
} else { } else {
@@ -323,7 +328,7 @@ int GPTDataCL::DoOptions(int argc, char* argv[]) {
JustLooking(0); JustLooking(0);
startSector = FindFirstInLargest(); startSector = FindFirstInLargest();
Align(&startSector); Align(&startSector);
endSector = FindLastInFree(startSector); endSector = FindLastInFree(startSector, alignEnd);
if (largestPartNum <= 0) if (largestPartNum <= 0)
largestPartNum = FindFirstFreePart() + 1; largestPartNum = FindFirstFreePart() + 1;
if (CreatePartition(largestPartNum - 1, startSector, endSector)) { if (CreatePartition(largestPartNum - 1, startSector, endSector)) {

View File

@@ -1,7 +1,7 @@
/* /*
Implementation of GPTData class derivative with popt-based command Implementation of GPTData class derivative with popt-based command
line processing line processing
Copyright (C) 2010-2013 Roderick W. Smith Copyright (C) 2010-2022 Roderick W. Smith
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -34,6 +34,7 @@ class GPTDataCL : public GPTData {
char *newPartInfo, *mbrParts, *twoParts, *outDevice, *typeCode; char *newPartInfo, *mbrParts, *twoParts, *outDevice, *typeCode;
char *partGUID, *diskGUID; char *partGUID, *diskGUID;
int alignment, deletePartNum, infoPartNum, largestPartNum, bsdPartNum; int alignment, deletePartNum, infoPartNum, largestPartNum, bsdPartNum;
bool alignEnd;
uint32_t tableSize; uint32_t tableSize;
poptContext poptCon; poptContext poptCon;

View File

@@ -1,7 +1,7 @@
/* /*
* Implementation of GPTData class derivative with curses-based text-mode * Implementation of GPTData class derivative with curses-based text-mode
* interaction * interaction
* Copyright (C) 2011-2018 Roderick W. Smith * Copyright (C) 2011-2022 Roderick W. Smith
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -430,12 +430,18 @@ void GPTDataCurses::Verify(void) {
// Create a new partition in the space pointed to by currentSpace. // Create a new partition in the space pointed to by currentSpace.
void GPTDataCurses::MakeNewPart(void) { void GPTDataCurses::MakeNewPart(void) {
uint64_t size, newFirstLBA = 0, newLastLBA = 0; uint64_t size, newFirstLBA = 0, newLastLBA = 0, lastAligned;
int partNum; int partNum;
char inLine[80]; char inLine[80];
move(LINES - 4, 0); move(LINES - 4, 0);
clrtobot(); clrtobot();
lastAligned = currentSpace->lastLBA + 1;
Align(&lastAligned);
lastAligned--;
// Discard end-alignment attempt if it's giving us an invalid end point....
if (!IsFree(lastAligned))
lastAligned = currentSpace->lastLBA;
while ((newFirstLBA < currentSpace->firstLBA) || (newFirstLBA > currentSpace->lastLBA)) { while ((newFirstLBA < currentSpace->firstLBA) || (newFirstLBA > currentSpace->lastLBA)) {
move(LINES - 4, 0); move(LINES - 4, 0);
clrtoeol(); clrtoeol();
@@ -445,10 +451,13 @@ void GPTDataCurses::MakeNewPart(void) {
echo(); echo();
getnstr(inLine, 79); getnstr(inLine, 79);
noecho(); noecho();
newFirstLBA = IeeeToInt(inLine, blockSize, currentSpace->firstLBA, currentSpace->lastLBA, newFirstLBA); newFirstLBA = IeeeToInt(inLine, blockSize, currentSpace->firstLBA, currentSpace->lastLBA, sectorAlignment, newFirstLBA);
Align(&newFirstLBA); Align(&newFirstLBA);
} // while } // while
size = currentSpace->lastLBA - newFirstLBA + 1; if (newFirstLBA > lastAligned)
size = currentSpace->lastLBA - newFirstLBA + 1;
else
size = lastAligned - newFirstLBA + 1;
while ((newLastLBA > currentSpace->lastLBA) || (newLastLBA < newFirstLBA)) { while ((newLastLBA > currentSpace->lastLBA) || (newLastLBA < newFirstLBA)) {
move(LINES - 3, 0); move(LINES - 3, 0);
clrtoeol(); clrtoeol();
@@ -456,7 +465,7 @@ void GPTDataCurses::MakeNewPart(void) {
echo(); echo();
getnstr(inLine, 79); getnstr(inLine, 79);
noecho(); noecho();
newLastLBA = newFirstLBA + IeeeToInt(inLine, blockSize, 1, size, size) - 1; newLastLBA = newFirstLBA + IeeeToInt(inLine, blockSize, 1, size, sectorAlignment, size) - 1;
} // while } // while
partNum = FindFirstFreePart(); partNum = FindFirstFreePart();
if (CreatePartition(partNum, newFirstLBA, newLastLBA)) { // created OK; set type code & name.... if (CreatePartition(partNum, newFirstLBA, newLastLBA)) { // created OK; set type code & name....

View File

@@ -1,5 +1,5 @@
/* /*
Copyright (C) 2010-2018 <Roderick W. Smith> Copyright (C) 2010-2022 <Roderick W. Smith>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -199,7 +199,7 @@ void GPTDataTextUI::MoveMainTable(void) {
// 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, lastAligned;
uint32_t firstFreePart = 0; uint32_t firstFreePart = 0;
ostringstream prompt1, prompt2, prompt3; ostringstream prompt1, prompt2, prompt3;
int partNum; int partNum;
@@ -229,7 +229,7 @@ void GPTDataTextUI::CreatePartition(void) {
prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = " prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = "
<< firstInLargest << ") or {+-}size{KMGTP}: "; << firstInLargest << ") or {+-}size{KMGTP}: ";
do { do {
sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, blockSize, prompt2.str()); sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt2.str());
} while (IsFree(sector) == 0); } while (IsFree(sector) == 0);
origSector = sector; origSector = sector;
if (Align(&sector)) { if (Align(&sector)) {
@@ -239,15 +239,15 @@ void GPTDataTextUI::CreatePartition(void) {
if (!beQuiet) if (!beQuiet)
cout << "Use 'l' on the experts' menu to adjust alignment\n"; cout << "Use 'l' on the experts' menu to adjust alignment\n";
} // if } // if
// Align(&sector); // Align sector to correct multiple
firstBlock = sector; firstBlock = sector;
// Get last block for new partitions... // Get last block for new partitions...
lastBlock = FindLastInFree(firstBlock); lastBlock = FindLastInFree(firstBlock, false);
lastAligned = FindLastInFree(firstBlock, true);
prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = " prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = "
<< lastBlock << ") or {+-}size{KMGTP}: "; << lastAligned << ") or {+-}size{KMGTP}: ";
do { do {
sector = GetSectorNum(firstBlock, lastBlock, lastBlock, blockSize, prompt3.str()); sector = GetSectorNum(firstBlock, lastBlock, lastAligned, prompt3.str());
} while (IsFree(sector) == 0); } while (IsFree(sector) == 0);
lastBlock = sector; lastBlock = sector;
@@ -548,6 +548,28 @@ int GPTDataTextUI::XFormToMBR(void) {
return protectiveMBR.DoMenu(); return protectiveMBR.DoMenu();
} // GPTDataTextUI::XFormToMBR() } // GPTDataTextUI::XFormToMBR()
// Obtains a sector number, between low and high, from the
// user, accepting values prefixed by "+" to add sectors to low,
// or the same with "K", "M", "G", "T", or "P" as suffixes to add
// kibibytes, mebibytes, gibibytes, tebibytes, or pebibytes,
// respectively. If a "-" prefix is used, use the high value minus
// the user-specified number of sectors (or KiB, MiB, etc.). Use the
// def value as the default if the user just hits Enter.
uint64_t GPTDataTextUI::GetSectorNum(uint64_t low, uint64_t high, uint64_t def,
const string & prompt) {
uint64_t response;
char line[255];
do {
cout << prompt;
cin.getline(line, 255);
if (!cin.good())
exit(5);
response = IeeeToInt(line, blockSize, low, high, sectorAlignment, def);
} while ((response < low) || (response > high));
return response;
} // GPTDataTextUI::GetSectorNum()
/****************************************************** /******************************************************
* * * *
* Display informational messages for the user.... * * Display informational messages for the user.... *

View File

@@ -1,6 +1,6 @@
/* /*
Implementation of GPTData class derivative with basic text-mode interaction Implementation of GPTData class derivative with basic text-mode interaction
Copyright (C) 2010-2018 Roderick W. Smith Copyright (C) 2010-2022 Roderick W. Smith
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@@ -55,6 +55,7 @@ class GPTDataTextUI : public GPTData {
void ShowDetails(void); void ShowDetails(void);
void MakeHybrid(void); void MakeHybrid(void);
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt);
// An informational function.... // An informational function....
void WarnAboutIffyMBRPart(int partNum); void WarnAboutIffyMBRPart(int partNum);

View File

@@ -154,7 +154,10 @@ to sectors that are multiples of this value, which defaults to 1 MiB (2048
on disks with 512-byte sectors) on freshly formatted disks. This alignment on disks with 512-byte sectors) on freshly formatted disks. This alignment
value is necessary to obtain optimum performance with Western Digital value is necessary to obtain optimum performance with Western Digital
Advanced Format and similar drives with larger physical than logical sector Advanced Format and similar drives with larger physical than logical sector
sizes, with some types of RAID arrays, and with SSD devices. sizes, with some types of RAID arrays, and with SSD devices. When the
\fI\-I\fR option is used, this same alignment value is used to determine
partition end points; but partitions end at one less than a multiple of this
value, to keep the partition length a multiple of this value.
.TP .TP
.B \-A, \-\-attributes=list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]] .B \-A, \-\-attributes=list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]
@@ -280,7 +283,7 @@ is usually correct for Windows partitions. If the active/bootable flag should
be set, you must do so in another program, such as \fBfdisk\fR. The \fBgdisk\fR be set, you must do so in another program, such as \fBfdisk\fR. The \fBgdisk\fR
program offers additional hybrid MBR creation options. program offers additional hybrid MBR creation options.
.TP .TP
.B \-i, \-\-info=partnum .B \-i, \-\-info=partnum
Show detailed partition information. The summary information produced by Show detailed partition information. The summary information produced by
the \fI\-p\fR command necessarily omits many details, such as the partition's the \fI\-p\fR command necessarily omits many details, such as the partition's
@@ -288,6 +291,18 @@ 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 \-I, \-\-align\-end
When possible, align the end points of partitions to one less than a
multiple of the alignment value. When both start and end points are aligned,
partitions should be multiples of the alignment value in size, which is
necessary for some partition encryption tools to function correctly. This
option applies to all partitions created \fBafter\fR this option on the
command line. Note that this alignment is not always possible; for instance,
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 \fBsgdisk\fR is asked
to create a partition in that space, then it will \fBnot\fR be end\-aligned.
.TP .TP
.B \-j, \-\-adjust\-main\-table=sector .B \-j, \-\-adjust\-main\-table=sector
Adjust the location of the main partition table. This value is normally 2, Adjust the location of the main partition table. This value is normally 2,

View File

@@ -3,7 +3,7 @@
// Primarily by Rod Smith, February 2009, but with a few functions // Primarily by Rod Smith, February 2009, but with a few functions
// copied from other sources (see attributions below). // copied from other sources (see attributions below).
/* This program is copyright (c) 2009-2018 by Roderick W. Smith. It is distributed /* This program is copyright (c) 2009-2022 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
@@ -113,34 +113,11 @@ char GetYN(void) {
return response; return response;
} // GetYN(void) } // GetYN(void)
// Obtains a sector number, between low and high, from the
// user, accepting values prefixed by "+" to add sectors to low,
// or the same with "K", "M", "G", "T", or "P" as suffixes to add
// kilobytes, megabytes, gigabytes, terabytes, or petabytes,
// respectively. If a "-" prefix is used, use the high value minus
// the user-specified number of sectors (or KiB, MiB, etc.). Use the
// def value as the default if the user just hits Enter. The sSize is
// the sector size of the device.
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize,
const string & prompt) {
uint64_t response;
char line[255];
do {
cout << prompt;
cin.getline(line, 255);
if (!cin.good())
exit(5);
response = IeeeToInt(line, sSize, low, high, def);
} while ((response < low) || (response > high));
return response;
} // GetSectorNum()
// Convert an IEEE-1541-2002 value (K, M, G, T, P, or E) to its equivalent in // Convert an IEEE-1541-2002 value (K, M, G, T, P, or E) to its equivalent in
// number of sectors. If no units are appended, interprets as the number // number of sectors. If no units are appended, interprets as the number
// of sectors; otherwise, interprets as number of specified units and // of sectors; otherwise, interprets as number of specified units and
// converts to sectors. For instance, with 512-byte sectors, "1K" converts // converts to sectors. For instance, with 512-byte sectors, "1K" converts
// to 2. If value includes a "+", adds low and subtracts 1; if SIValue // to 2. If value includes a "+", adds low and subtracts 1; if inValue
// inclues a "-", subtracts from high. If IeeeValue is empty, returns def. // inclues a "-", subtracts from high. If IeeeValue is empty, returns def.
// Returns final sector value. In case inValue is invalid, returns 0 (a // Returns final sector value. In case inValue is invalid, returns 0 (a
// sector value that's always in use on GPT and therefore invalid); and if // sector value that's always in use on GPT and therefore invalid); and if
@@ -153,7 +130,7 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize,
// 0 values. The result is that IeeeToInt() returns UINT64_MAX when // 0 values. The result is that IeeeToInt() returns UINT64_MAX when
// compiled with GCC (and so the value is rejected), whereas when VC++ // compiled with GCC (and so the value is rejected), whereas when VC++
// is used, the default value is returned. // is used, the default value is returned.
uint64_t IeeeToInt(string inValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def) { uint64_t IeeeToInt(string inValue, uint64_t sSize, uint64_t low, uint64_t high, uint32_t sectorAlignment, uint64_t def) {
uint64_t response = def, bytesPerUnit, mult = 1, divide = 1; uint64_t response = def, bytesPerUnit, mult = 1, divide = 1;
size_t foundAt = 0; size_t foundAt = 0;
char suffix = ' ', plusFlag = ' '; char suffix = ' ', plusFlag = ' ';
@@ -208,11 +185,12 @@ uint64_t IeeeToInt(string inValue, uint64_t sSize, uint64_t low, uint64_t high,
} // if/elseif } // if/elseif
if (plusFlag == '+') { if (plusFlag == '+') {
// Recompute response based on low part of range (if default == high // Recompute response based on low part of range (if default is within
// value, which should be the case when prompting for the end of a // sectorAlignment sectors of high, which should be the case when
// range) or the defaut value (if default != high, which should be // prompting for the end of a range) or the defaut value (if default is
// the case for the first sector of a partition). // further away from the high value, which should be the case for the
if (def == high) { // first sector of a partition).
if ((high - def) < sectorAlignment) {
if (response > 0) if (response > 0)
response--; response--;
if (response > (UINT64_MAX - low)) if (response > (UINT64_MAX - low))

View File

@@ -1,4 +1,4 @@
/* This program is copyright (c) 2009-2018 by Roderick W. Smith. It is distributed /* This program is copyright (c) 2009-2022 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#ifndef __GPTSUPPORT #ifndef __GPTSUPPORT
@@ -8,7 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#define GPTFDISK_VERSION "1.0.8" #define GPTFDISK_VERSION "1.0.8.2"
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
// Darwin (Mac OS) & FreeBSD: disk IOCTLs are different, and there is no lseek64 // Darwin (Mac OS) & FreeBSD: disk IOCTLs are different, and there is no lseek64
@@ -74,8 +74,7 @@ using namespace std;
string ReadString(void); string ReadString(void);
uint64_t GetNumber(uint64_t low, uint64_t high, uint64_t 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 IeeeToInt(string IeeeValue, uint64_t sSize, uint64_t low, uint64_t high, uint32_t sectorAlignment, uint64_t def = 0);
uint64_t IeeeToInt(string IeeeValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def = 0);
string BytesToIeee(uint64_t size, uint32_t sectorSize); string BytesToIeee(uint64_t size, uint32_t sectorSize);
unsigned char StrToHex(const string & input, unsigned int position); unsigned char StrToHex(const string & input, unsigned int position);
int IsHex(string input); // Returns 1 if input can be hexadecimal number.... int IsHex(string input); // Returns 1 if input can be hexadecimal number....