Version 0.6.12 release; mostly changes in support for disks with other

than 512-byte sectors.
This commit is contained in:
srs5694
2010-10-07 13:00:45 -04:00
parent ab4b043839
commit 0873e9d0e9
18 changed files with 286 additions and 171 deletions

23
NEWS
View File

@@ -1,3 +1,26 @@
0.6.12 (10/7/2010):
-------------------
- Adjusted alignment code to use 1 MiB alignment by default for drives with
other than 512-byte sector sizes. (Previous versions increased this --
for instance, to 4 MiB for drives with 2048-byte logical sector size.)
- Entry of non-hexadecimal value for partition type code now causes
re-prompting for a new value, fixing a recently-introduced minor bug.
- Fixed bug in sector entry using K/M/G/T/P suffixes on disks with
other-than-512-byte sector numbers.
- Added "P" (PiB, pebibyte) suffix to suffixes accepted in entering
partition sizes.
- Fixed bug that caused sgdisk to segfault if fed the (invalid)
"-A show" parameter. Now it terminates with a complaint about an invalid
partition number 0.
- Removed warning when running on big-endian hardware, since this
support has been present for quite a while with no bug reports.
0.6.11 (9/25/2010):
-------------------

View File

@@ -19,9 +19,31 @@
using namespace std;
string Attributes::atNames[NUM_ATR];
Attributes::staticInit Attributes::staticInitializer;
int Attributes::numAttrs = 0;
//Attributes::staticInit Attributes::staticInitializer;
Attributes::staticInit::staticInit (void) {
// Default constructor
Attributes::Attributes(void) {
numAttrs++;
if (numAttrs == 1)
Setup();
attributes = 0;
} // constructor
// Alternate constructor
Attributes::Attributes(const uint64_t a) {
numAttrs++;
if (numAttrs == 1)
Setup();
attributes = a;
} // alternate constructor
// Destructor.
Attributes::~Attributes(void) {
numAttrs--;
} // Attributes destructor
void Attributes::Setup(void) {
ostringstream temp;
// Most bits are undefined, so start by giving them an
@@ -33,17 +55,13 @@ Attributes::staticInit::staticInit (void) {
} // for
// Now reset those names that are defined....
Attributes::atNames[0] = "system partition"; // required for computer to operate
Attributes::atNames[1] = "hide from EFI";
Attributes::atNames[2] = "legacy BIOS bootable";
Attributes::atNames[60] = "read-only";
Attributes::atNames[62] = "hidden";
Attributes::atNames[63] = "do not automount";
} // Attributes::staticInit::staticInit
// Destructor.
Attributes::~Attributes(void) {
} // Attributes destructor
atNames[0] = "system partition"; // required for computer to operate
atNames[1] = "hide from EFI";
atNames[2] = "legacy BIOS bootable";
atNames[60] = "read-only";
atNames[62] = "hidden";
atNames[63] = "do not automount";
} // Attributes::Setup()
// Display current attributes to user
void Attributes::DisplayAttributes(void) {
@@ -57,7 +75,7 @@ void Attributes::DisplayAttributes(void) {
cout << hex << attributes << dec << ". Set fields are:\n";
for (i = 0; i < NUM_ATR; i++) {
if ((UINT64_C(1) << i) & attributes) {
cout << i << " (" << Attributes::GetAttributeName(i) << ")" << "\n";
cout << i << " (" << GetAttributeName(i) << ")" << "\n";
numSet++;
} // if
} // for
@@ -67,6 +85,21 @@ void Attributes::DisplayAttributes(void) {
cout << "\n";
} // Attributes::DisplayAttributes()
// Display attributes for a partition. Note that partNum is just passed for
// immediate display; it's not used to access a particular partition.
void Attributes::ShowAttributes(const uint32_t partNum) {
uint32_t bitNum;
bool bitset;
for (bitNum = 0; bitNum < 64; bitNum++) {
bitset = (UINT64_C(1) << bitNum) & attributes;
if (bitset) {
cout << partNum+1 << ":" << bitNum << ":" << bitset
<< " (" << GetAttributeName(bitNum) << ")" << endl;
} // if
} // for
} // Attributes::ShowAttributes
// Prompt user for attribute changes
void Attributes::ChangeAttributes(void) {
int response;
@@ -78,7 +111,8 @@ void Attributes::ChangeAttributes(void) {
do {
DisplayAttributes();
response = GetNumber(0, NUM_ATR, -1, "Toggle which attribute field (0-63, 64 to exit): ");
response = GetNumber(0, NUM_ATR, 64,
"Toggle which attribute field (0-63, 64 or <Enter> to exit): ");
if (response != 64) {
bitValue = UINT64_C(1) << response; // Find the integer value of the bit
if (bitValue & attributes) { // bit is set
@@ -104,19 +138,6 @@ void Attributes::ListAttributes(void) {
} // for
} // Attributes::ListAttributes
void Attributes::ShowAttributes(const uint32_t partNum) {
uint32_t bitNum;
bool bitset;
for (bitNum = 0; bitNum < 64; bitNum++) {
bitset = (UINT64_C(1) << bitNum) & attributes;
if (bitset) {
cout << partNum+1 << ":" << bitNum << ":" << bitset
<< " (" << Attributes::GetAttributeName(bitNum) << ")" << endl;
} // if
} // for
} // Attributes::ShowAttributes
// multifaceted attributes access
// returns true upon success, false upon failure
bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) {
@@ -190,3 +211,15 @@ bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attri
return true;
} // Attributes::OperateOnAttributes()
/*******************************
* *
* Non-class support functions *
* *
*******************************/
// Display attributes
ostream & operator<<(ostream & os, const Attributes & data) {
os << data.GetAttributes();
return os;
} // operator<<()

View File

@@ -13,27 +13,29 @@
using namespace std;
class Attributes {
private:
class staticInit {public: staticInit (void);};
static string atNames[NUM_ATR];
static Attributes::staticInit staticInitializer;
protected:
static string atNames[NUM_ATR];
static int numAttrs;
void Setup(void);
uint64_t attributes;
public:
Attributes(const uint64_t a = 0) {SetAttributes (a);}
Attributes(void);
Attributes(const uint64_t a);
~Attributes(void);
void SetAttributes(const uint64_t a) {attributes = a;}
uint64_t GetAttributes(void) {return attributes;}
void operator=(uint64_t a) {attributes = a;}
uint64_t GetAttributes(void) const {return attributes;}
void DisplayAttributes(void);
void ChangeAttributes(void);
void ShowAttributes(const uint32_t partNum);
void ChangeAttributes(void);
bool OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits);
static const string& GetAttributeName(const uint32_t bitNum) {return atNames [bitNum];}
static void ListAttributes(void);
}; // class Attributes
ostream & operator<<(ostream & os, const Attributes & data);
#endif

View File

@@ -1,11 +1,11 @@
Summary: An fdisk-like partitioning tool for GPT disks
Name: gdisk
Version: 0.6.11
Version: 0.6.12
Release: 1%{?dist}
License: GPLv2
URL: http://www.rodsbooks.com/gdisk
Group: Applications/System
Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.11.tgz
Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.12.tgz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%description
@@ -40,5 +40,5 @@ rm -rf $RPM_BUILD_ROOT
%doc %{_mandir}/man8*
%changelog
* Sat Sep 25 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.11
- Created spec file for 0.6.11 release
* Thu Oct 7 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.12
- Created spec file for 0.6.12 release

21
gdisk.8
View File

@@ -1,6 +1,6 @@
.\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH "GDISK" "8" "0.6.11" "Roderick W. Smith" "GPT fdisk Manual"
.TH "GDISK" "8" "0.6.12" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS"
@@ -197,15 +197,16 @@ Create a new partition. This command is modelled after the equivalent
\fBfdisk\fR option, although some differences exist. You enter a partition
number, starting sector, and an ending sector. Both start and end sectors
can be specified in absolute terms as sector numbers or as positions
measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T);
for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of
the disk. You can specify locations relative to the start or end of the
specified default range by preceding the number by a '+' or '\-' symbol, as
in \fI\fB+2G\fR\fR to specify a point 2GiB after the 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 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 sector.
measured in kibibytes (K), mebibytes (M), gibibytes (G), tebibytes (T), or
pebibytes (P); for instance, \fI\fB40M\fR\fR specifies a position 40MiB
from the start of the disk. You can specify locations relative to the start
or end of the specified default range by preceding the number by a '+' or
'\-' symbol, as in \fI\fB+2G\fR\fR to specify a point 2GiB after the
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
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
sector.
.TP
.B o

76
gpt.cc
View File

@@ -58,7 +58,7 @@ GPTData::GPTData(void) {
secondPartsCrcOk = 0;
apmFound = 0;
bsdFound = 0;
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default
beQuiet = 0;
whichWasUsed = use_new;
srand((unsigned int) time(NULL));
@@ -81,7 +81,7 @@ GPTData::GPTData(string filename) {
secondPartsCrcOk = 0;
apmFound = 0;
bsdFound = 0;
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default
beQuiet = 0;
whichWasUsed = use_new;
srand((unsigned int) time(NULL));
@@ -248,9 +248,9 @@ int GPTData::Verify(void) {
if (problems == 0) {
totalFree = FindFreeBlocks(&numSegments, &largestSegment);
cout << "No problems found. " << totalFree << " free sectors ("
<< BytesToSI(totalFree * (uint64_t) blockSize) << ") available in "
<< BytesToSI(totalFree, blockSize) << ") available in "
<< numSegments << "\nsegments, the largest of which is "
<< largestSegment << " (" << BytesToSI(largestSegment * (uint64_t) blockSize)
<< largestSegment << " (" << BytesToSI(largestSegment, blockSize)
<< ") in size.\n";
} else {
cout << "\nIdentified " << problems << " problems!\n";
@@ -551,7 +551,7 @@ int GPTData::FindInsanePartitions(void) {
} // if
if (partitions[i].GetLastLBA() >= diskSize) {
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
} // for
return problems;
@@ -876,11 +876,10 @@ int GPTData::SaveGPTData(int quiet, string filename) {
int allOK = 1, littleEndian;
char answer;
if (filename == "")
filename = device;
littleEndian = IsLittleEndian();
if (filename == "")
filename = device;
if (filename == "") {
cerr << "Device not defined.\n";
} // if
@@ -1113,16 +1112,12 @@ int GPTData::LoadGPTBackup(const string & filename) {
if ((val = CheckHeaderValidity()) > 0) {
if (val == 2) { // only backup header seems to be good
SetGPTSize(secondHeader.numParts);
// numParts = secondHeader.numParts;
sizeOfEntries = secondHeader.sizeOfPartitionEntries;
} else { // main header is OK
SetGPTSize(mainHeader.numParts);
// numParts = mainHeader.numParts;
sizeOfEntries = mainHeader.sizeOfPartitionEntries;
} // if/else
// SetGPTSize(numParts);
if (secondHeader.currentLBA != diskSize - UINT64_C(1)) {
cout << "Warning! Current disk size doesn't match that of the backup!\n"
<< "Adjusting sizes to match, but subsequent problems are possible!\n";
@@ -1266,7 +1261,7 @@ void GPTData::DisplayGPTData(void) {
uint64_t temp, totalFree;
cout << "Disk " << device << ": " << diskSize << " sectors, "
<< BytesToSI(diskSize * blockSize) << "\n";
<< BytesToSI(diskSize, blockSize) << "\n";
cout << "Logical sector size: " << blockSize << " bytes\n";
cout << "Disk identifier (GUID): " << mainHeader.diskGUID << "\n";
cout << "Partition table holds up to " << numParts << " entries\n";
@@ -1275,7 +1270,7 @@ void GPTData::DisplayGPTData(void) {
totalFree = FindFreeBlocks(&i, &temp);
cout << "Partitions will be aligned on " << sectorAlignment << "-sector boundaries\n";
cout << "Total free space is " << totalFree << " sectors ("
<< BytesToSI(totalFree * (uint64_t) blockSize) << ")\n";
<< BytesToSI(totalFree, blockSize) << ")\n";
cout << "\nNumber Start (sector) End (sector) Size Code Name\n";
for (i = 0; i < numParts; i++) {
partitions[i].ShowSummary(i, blockSize);
@@ -1284,7 +1279,7 @@ void GPTData::DisplayGPTData(void) {
// Show detailed information on the specified partition
void GPTData::ShowPartDetails(uint32_t partNum) {
if (partitions[partNum].GetFirstLBA() != 0) {
if (!IsFreePartNum(partNum)) {
partitions[partNum].ShowDetails(blockSize);
} else {
cout << "Partition #" << partNum + 1 << " does not exist.";
@@ -1780,7 +1775,10 @@ int GPTData::ClearGPTData(void) {
for (i = 0; i < GPT_RESERVED; i++) {
mainHeader.reserved2[i] = '\0';
} // for
sectorAlignment = DEFAULT_ALIGNMENT;
if (blockSize > 0)
sectorAlignment = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize;
else
sectorAlignment = DEFAULT_ALIGNMENT;
// Now some semi-static items (computed based on end of disk)
mainHeader.backupLBA = diskSize - UINT64_C(1);
@@ -2174,31 +2172,37 @@ int GPTData::IsFreePartNum(uint32_t partNum) {
// Set partition alignment value; partitions will begin on multiples of
// the specified value
void GPTData::SetAlignment(uint32_t n) {
sectorAlignment = n;
if (n > 0)
sectorAlignment = n;
else
cerr << "Attempt to set partition alignment to 0!\n";
} // GPTData::SetAlignment()
// Compute sector alignment based on the current partitions (if any). Each
// partition's starting LBA is examined, and if it's divisible by a power-of-2
// value less than or equal to the DEFAULT_ALIGNMENT value, but not by the
// previously-located alignment value, then the alignment value is adjusted
// down. If the computed alignment is less than 8 and the disk is bigger than
// SMALLEST_ADVANCED_FORMAT, resets it to 8. This is a safety measure for WD
// Advanced Format and similar drives. If no partitions are defined, the
// alignment value is set to DEFAULT_ALIGNMENT (2048). The result is that new
// value less than or equal to the DEFAULT_ALIGNMENT value (adjusted for the
// sector size), but not by the previously-located alignment value, then the
// alignment value is adjusted down. If the computed alignment is less than 8
// and the disk is bigger than SMALLEST_ADVANCED_FORMAT, resets it to 8. This
// is a safety measure for WD Advanced Format and similar drives. If no partitions
// are defined, the alignment value is set to DEFAULT_ALIGNMENT (2048) (or an
// adjustment of that based on the current sector size). The result is that new
// drives are aligned to 2048-sector multiples but the program won't complain
// about other alignments on existing disks unless a smaller-than-8 alignment
// is used on small disks (as safety for WD Advanced Format drives).
// is used on big disks (as safety for WD Advanced Format drives).
// Returns the computed alignment value.
uint32_t GPTData::ComputeAlignment(void) {
uint32_t i = 0, found, exponent = 31;
uint32_t align = DEFAULT_ALIGNMENT;
exponent = (uint32_t) log2(DEFAULT_ALIGNMENT);
if (blockSize > 0)
align = DEFAULT_ALIGNMENT * SECTOR_SIZE / blockSize;
exponent = (uint32_t) log2(align);
for (i = 0; i < numParts; i++) {
if (partitions[i].IsUsed()) {
found = 0;
while (!found) {
align = UINT64_C(1)<<exponent;
align = UINT64_C(1) << exponent;
if ((partitions[i].GetFirstLBA() % align) == 0) {
found = 1;
} else {
@@ -2207,9 +2211,9 @@ uint32_t GPTData::ComputeAlignment(void) {
} // while
} // if
} // for
if ((align < 8) && (diskSize >= SMALLEST_ADVANCED_FORMAT))
align = 8;
SetAlignment(align);
if ((align < MIN_AF_ALIGNMENT) && (diskSize >= SMALLEST_ADVANCED_FORMAT))
align = MIN_AF_ALIGNMENT;
sectorAlignment = align;
return align;
} // GPTData::ComputeAlignment()
@@ -2296,14 +2300,12 @@ int GPTData::ManageAttributes(int partNum, const string & command, const string
// Show all attributes for a specified partition....
void GPTData::ShowAttributes(const uint32_t partNum) {
Attributes theAttr (partitions[partNum].GetAttributes());
theAttr.ShowAttributes(partNum);
partitions[partNum].ShowAttributes(partNum);
} // GPTData::ShowAttributes
// Show whether a single attribute bit is set (terse output)...
void GPTData::GetAttribute(const uint32_t partNum, const string& attributeBits) {
Attributes theAttr (partitions[partNum].GetAttributes());
theAttr.OperateOnAttributes(partNum, "get", attributeBits);
partitions[partNum].GetAttributes().OperateOnAttributes(partNum, "get", attributeBits);
} // GPTData::GetAttribute
@@ -2361,10 +2363,10 @@ int SizesOK(void) {
allOK = 0;
} // if
// Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware
if (IsLittleEndian() == 0) {
cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"
" tested!\n";
} // if
// if (IsLittleEndian() == 0) {
// cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"
// " tested!\n";
// } // if
return (allOK);
} // SizesOK()

11
gpt.h
View File

@@ -16,7 +16,7 @@
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
#define GPTFDISK_VERSION "0.6.11"
#define GPTFDISK_VERSION "0.6.12"
// Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
// numbered value to refer to partition numbers. (Most will be 0 or positive,
@@ -27,11 +27,10 @@
// Default values for sector alignment
#define DEFAULT_ALIGNMENT 2048
#define MAX_ALIGNMENT 65536
#define MIN_AF_ALIGNMENT 8
// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
// cutoff
//#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
// Now ~596GiB (640MB), since WD has introduced a smaller Advanced Format drive
// Below constant corresponds to a ~596GiB (640MB) disk, since WD has
// introduced a smaller Advanced Format drive
#define SMALLEST_ADVANCED_FORMAT UINT64_C(1250263728)
using namespace std;
@@ -90,7 +89,7 @@ protected:
int secondPartsCrcOk;
int apmFound; // set to 1 if APM detected
int bsdFound; // set to 1 if BSD disklabel detected in MBR
uint32_t sectorAlignment; // Start & end partitions at multiples of sectorAlignment
uint32_t sectorAlignment; // Start partitions at multiples of sectorAlignment
int beQuiet;
WhichToUse whichWasUsed;

View File

@@ -150,7 +150,7 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
int i;
if (firstLBA != 0) {
sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1));
sizeInSI = BytesToSI(lastLBA - firstLBA + 1, blockSize);
cout.fill(' ');
cout.width(4);
cout << partNum + 1 << " ";
@@ -158,7 +158,7 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
cout << firstLBA << " ";
cout.width(14);
cout << lastLBA << " ";
cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
cout << BytesToSI(lastLBA - firstLBA + 1, blockSize) << " ";
for (i = 0; i < 10 - (int) sizeInSI.length(); i++)
cout << " ";
cout.fill('0');
@@ -182,12 +182,12 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
cout << "Partition unique GUID: " << uniqueGUID << "\n";
cout << "First sector: " << firstLBA << " (at "
<< BytesToSI(firstLBA * blockSize) << ")\n";
<< BytesToSI(firstLBA, blockSize) << ")\n";
cout << "Last sector: " << lastLBA << " (at "
<< BytesToSI(lastLBA * blockSize) << ")\n";
<< BytesToSI(lastLBA, blockSize) << ")\n";
size = (lastLBA - firstLBA + 1);
cout << "Partition size: " << size << " sectors ("
<< BytesToSI(size * ((uint64_t) blockSize)) << ")\n";
<< BytesToSI(size, blockSize) << ")\n";
cout << "Attribute flags: ";
cout.fill('0');
cout.width(16);

View File

@@ -21,6 +21,7 @@
#include "support.h"
#include "parttypes.h"
#include "guid.h"
#include "attributes.h"
using namespace std;
@@ -43,7 +44,8 @@ class GPTPart {
GUIDData uniqueGUID;
uint64_t firstLBA;
uint64_t lastLBA;
uint64_t attributes;
Attributes attributes;
// uint64_t attributes;
unsigned char name[NAME_SIZE];
public:
GPTPart(void);
@@ -57,7 +59,8 @@ class GPTPart {
uint64_t GetFirstLBA(void) const {return firstLBA;}
uint64_t GetLastLBA(void) const {return lastLBA;}
uint64_t GetLengthLBA(void);
uint64_t GetAttributes(void) {return attributes;}
Attributes GetAttributes(void) {return attributes;}
void ShowAttributes(uint32_t partNum) {attributes.ShowAttributes(partNum);}
string GetDescription(void);
int IsUsed(void);
@@ -69,6 +72,7 @@ class GPTPart {
void SetFirstLBA(uint64_t f) {firstLBA = f;}
void SetLastLBA(uint64_t l) {lastLBA = l;}
void SetAttributes(uint64_t a) {attributes = a;}
void SetAttributes(void) {attributes.ChangeAttributes();}
void SetName(const string & n);
void SetDefaultDescription(void);

View File

@@ -207,9 +207,9 @@ void GPTDataTextUI::CreatePartition(void) {
// Get first block for new partition...
prompt2 << "First sector (" << firstBlock << "-" << lastBlock << ", default = "
<< firstInLargest << ") or {+-}size{KMGT}: ";
<< firstInLargest << ") or {+-}size{KMGTP}: ";
do {
sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt2.str());
sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, blockSize, prompt2.str());
} while (IsFree(sector) == 0);
origSector = sector;
if (Align(&sector)) {
@@ -225,9 +225,9 @@ void GPTDataTextUI::CreatePartition(void) {
// Get last block for new partitions...
lastBlock = FindLastInFree(firstBlock);
prompt3 << "Last sector (" << firstBlock << "-" << lastBlock << ", default = "
<< lastBlock << ") or {+-}size{KMGT}: ";
<< lastBlock << ") or {+-}size{KMGTP}: ";
do {
sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt3.str());
sector = GetSectorNum(firstBlock, lastBlock, lastBlock, blockSize, prompt3.str());
} while (IsFree(sector) == 0);
lastBlock = sector;
@@ -271,11 +271,13 @@ void GPTDataTextUI::ChangePartType(void) {
// Partition attributes seem to be rarely used, but I want a way to
// adjust them for completeness....
void GPTDataTextUI::SetAttributes(uint32_t partNum) {
Attributes theAttr;
// Attributes theAttr;
theAttr.SetAttributes(partitions[partNum].GetAttributes());
partitions[partNum].SetAttributes();
/* theAttr = partitions[partNum].GetAttributes();
// theAttr.SetAttributes(partitions[partNum].GetAttributes());
theAttr.ChangeAttributes();
partitions[partNum].SetAttributes(theAttr.GetAttributes());
partitions[partNum].SetAttributes(theAttr.GetAttributes()); */
} // GPTDataTextUI::SetAttributes()
// Ask user for two partition numbers and swap them in the table. Note that

View File

@@ -202,7 +202,7 @@ string GUIDData::DeleteSpaces(string s) {
// Display a GUID as a string....
ostream & operator<<(ostream & os, const GUIDData & data) {
string asString;
// string asString;
os << data.AsString();
return os;

2
mbr.cc
View File

@@ -444,7 +444,7 @@ void MBRData::DisplayMBRData(int maxParts) {
cout.fill(' ');
} // for
cout << "\nDisk size is " << diskSize << " sectors ("
<< BytesToSI(diskSize * (uint64_t) blockSize) << ")\n";
<< BytesToSI(diskSize, blockSize) << ")\n";
} // MBRData::DisplayMBRData()
// Displays the state, as a word, on stdout. Used for debugging & to

View File

@@ -600,8 +600,8 @@ void PartNotes::ShowSummary(void) {
cout << " * ";
else
cout << " ";
sizeInSI = BytesToSI(blockSize * (gptParts[theNote->gptPartNum].GetLastLBA() -
gptParts[theNote->gptPartNum].GetFirstLBA() + 1));
sizeInSI = BytesToSI((gptParts[theNote->gptPartNum].GetLastLBA() -
gptParts[theNote->gptPartNum].GetFirstLBA() + 1), blockSize);
cout << " " << sizeInSI;
for (j = 0; j < 12 - (int) sizeInSI.length(); j++)
cout << " ";

View File

@@ -192,13 +192,16 @@ int PartType::AddType(uint16_t mbrType, const char * guidData, const char * name
// Assignment operator by string. If the original string is short,
// interpret it as a gdisk hex code; if it's longer, interpret it as
// a direct entry of a GUID value....
// a direct entry of a GUID value. If a short string isn't a hex
// number, do nothing.
PartType & PartType::operator=(const string & orig) {
uint32_t hexCode;
if (orig.length() < 32) {
sscanf(orig.c_str(), "%x", &hexCode);
*this = hexCode;
if (IsHex(orig)) {
sscanf(orig.c_str(), "%x", &hexCode);
*this = hexCode;
} // if
} else {
GUIDData::operator=(orig);
} // if/else hexCode or GUID

View File

@@ -1,6 +1,6 @@
.\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH "SGDISK" "8" "0.6.11" "Roderick W. Smith" "GPT fdisk Manual"
.TH "SGDISK" "8" "0.6.12" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS"
@@ -314,12 +314,12 @@ convert partitions that start above the 2TiB mark or that are larger than
.TP
.B \-n, \-\-new=partnum:start:end
Create a new partition. You enter a partition
number, starting sector, and an ending sector. Both start and end sectors
can be specified in absolute terms as sector numbers or as positions
measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T);
for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of
the disk. You can specify locations relative to the start or end of the
Create a new partition. You enter a partition number, starting sector, and
an ending sector. Both start and end sectors can be specified in absolute
terms as sector numbers or as positions measured in kibibytes (K),
mebibytes (M), gibibytes (G), tebibytes (T), or pebibytes (P); for
instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of the
disk. You can specify locations relative to the start or end of the
specified default range by preceding the number by a '+' or '\-' symbol, as
in \fI\fB+2G\fR\fR to specify a point 2GiB after the default start sector,
or \fI\fB\-200M\fR\fR to specify a point 200MiB before the last available

View File

@@ -136,20 +136,26 @@ int main(int argc, char *argv[]) {
case 'A': {
if (cmd != "list") {
partNum = (int) GetInt(attributeOperation, 1) - 1;
switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2),
GetString(attributeOperation, 3))) {
case -1:
saveData = 0;
neverSaveData = 1;
break;
case 1:
theGPT.JustLooking(0);
saveData = 1;
break;
default:
break;
} // switch
} // if
if ((partNum >= 0) && (partNum < (int) theGPT.GetNumParts())) {
switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2),
GetString(attributeOperation, 3))) {
case -1:
saveData = 0;
neverSaveData = 1;
break;
case 1:
theGPT.JustLooking(0);
saveData = 1;
break;
default:
break;
} // switch
} else {
cerr << "Error: Invalid partition number " << partNum + 1 << "\n";
saveData = 0;
neverSaveData = 1;
} // if/else reasonable partition #
} // if (cmd != "list")
break;
} // case 'A':
case 'a':

View File

@@ -41,8 +41,7 @@ int GetNumber(int low, int high, int def, const string & prompt) {
char line[255];
if (low != high) { // bother only if low and high differ...
response = low - 1; // force one loop by setting response outside range
while ((response < low) || (response > high)) {
do {
cout << prompt;
cin.getline(line, 255);
num = sscanf(line, "%d", &response);
@@ -52,7 +51,7 @@ int GetNumber(int low, int high, int def, const string & prompt) {
} else { // user hit enter; return default
response = def;
} // if/else
} // while
} while ((response < low) || (response > high));
} else { // low == high, so return this value
cout << "Using " << low << "\n";
response = low;
@@ -63,33 +62,40 @@ int GetNumber(int low, int high, int def, const string & prompt) {
// Gets a Y/N response (and converts lowercase to uppercase)
char GetYN(void) {
char line[255];
char response = '\0';
char response;
char *junk;
while ((response != 'Y') && (response != 'N')) {
do {
cout << "(Y/N): ";
junk = fgets(line, 255, stdin);
sscanf(line, "%c", &response);
if (response == 'y') response = 'Y';
if (response == 'n') response = 'N';
} // while
if (response == 'y')
response = 'Y';
if (response == 'n')
response = 'N';
} while ((response != 'Y') && (response != 'N'));
return response;
} // 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", or "T" as suffixes to add
// kilobytes, megabytes, gigabytes, or terabytes, 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 GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt) {
uint64_t response, mult = 1;
// 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, mult = 1, divide = 1;
int plusFlag = 0;
char suffix, line[255];
response = low - 1; // Ensure one pass by setting a too-low initial value
while ((response < low) || (response > high)) {
if (sSize == 0) {
sSize = SECTOR_SIZE;
cerr << "Bug: Sector size invalid in GetSectorNum()!\n";
} // if
do {
cout << prompt;
cin.getline(line, 255);
@@ -124,26 +130,36 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string &
switch (suffix) {
case 'K':
case 'k':
mult = (uint64_t) 1024 / SECTOR_SIZE;
mult = UINT64_C(1024) / sSize;
divide = sSize / UINT64_C(1024);
break;
break;
case 'M':
case 'm':
mult = (uint64_t) 1048576 / SECTOR_SIZE;
case 'm':
mult = UINT64_C(1048576) / sSize;
divide = sSize / UINT64_C(1048576);
break;
case 'G':
case 'g':
mult = (uint64_t) 1073741824 / SECTOR_SIZE;
mult = UINT64_C(1073741824) / sSize;
break;
case 'T':
case 't':
mult = ((uint64_t) 1073741824 * (uint64_t) 1024) / (uint64_t) SECTOR_SIZE;
case 't':
mult = UINT64_C(1099511627776) / sSize;
break;
case 'P':
case 'p':
mult = UINT64_C(1125899906842624) / sSize;
break;
default:
mult = 1;
} // switch
// Adjust response based on multiplier and plus flag, if present
response *= mult;
if (mult > 1)
response *= mult;
else if (divide > 1)
response /= divide;
if (plusFlag == 1) {
// Recompute response based on low part of range (if default = high
// value, which should be the case when prompting for the end of a
@@ -157,19 +173,20 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string &
if (plusFlag == -1) {
response = high - response;
} // if
} // while
} while ((response < low) || (response > high));
return response;
} // GetSectorNum()
// Takes a size in bytes (in size) and converts this to a size in
// SI units (KiB, MiB, GiB, TiB, or PiB), returned in C++ string
// form
string BytesToSI(uint64_t size) {
// Takes a size and converts this to a size in SI units (KiB, MiB, GiB,
// TiB, or PiB), returned in C++ string form. The size is either in units
// of the sector size or, if that parameter is omitted, in bytes.
// (sectorSize defaults to 1).
string BytesToSI(uint64_t size, uint32_t sectorSize) {
string units;
ostringstream theValue;
float sizeInSI;
sizeInSI = (float) size;
sizeInSI = (float) size * (float) sectorSize;
units = " bytes";
if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0;
@@ -215,6 +232,29 @@ unsigned char StrToHex(const string & input, unsigned int position) {
return retval;
} // StrToHex()
// Returns 1 if input can be interpreted as a hexadecimal number --
// all characters must be spaces, digits, or letters A-F (upper- or
// lower-case), with at least one valid hexadecimal digit; otherwise
// returns 0.
int IsHex(const string & input) {
int isHex = 1, foundHex = 0, i;
for (i = 0; i < (int) input.length(); i++) {
if ((input[i] < '0') || (input[i] > '9')) {
if ((input[i] < 'A') || (input[i] > 'F')) {
if ((input[i] < 'a') || (input[i] > 'f')) {
if ((input[i] != ' ') && (input[i] != '\n')) {
isHex = 0;
}
} else foundHex = 1;
} else foundHex = 1;
} else foundHex = 1;
} // for
if (!foundHex)
isHex = 0;
return isHex;
} // IsHex()
// Return 1 if the CPU architecture is little endian, 0 if it's big endian....
int IsLittleEndian(void) {
int littleE = 1; // assume little-endian (Intel-style)

View File

@@ -2,7 +2,6 @@
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
//#include <unistd.h>
#include <stdlib.h>
#include <string>
@@ -50,9 +49,10 @@ using namespace std;
int GetNumber(int low, int high, int def, const string & prompt);
char GetYN(void);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt);
string BytesToSI(uint64_t size);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
string BytesToSI(uint64_t size, uint32_t sectorSize = 1);
unsigned char StrToHex(const string & input, unsigned int position);
int IsHex(const string & input); // Returns 1 if input can be hexadecimal number....
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue