Version 0.6.12 release; mostly changes in support for disks with other
than 512-byte sectors.
diff --git a/NEWS b/NEWS
index a2afa17..f941e24 100644
--- a/NEWS
+++ b/NEWS
@@ -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):
-------------------
diff --git a/attributes.cc b/attributes.cc
index f068e6d..07f909a 100644
--- a/attributes.cc
+++ b/attributes.cc
@@ -19,11 +19,33 @@
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
// appropriate name
for (int i = 0; i < NUM_ATR; i++) {
@@ -33,17 +55,13 @@
} // 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 @@
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 @@
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 @@
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 @@
} // 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 @@
return true;
} // Attributes::OperateOnAttributes()
+
+/*******************************
+* *
+* Non-class support functions *
+* *
+*******************************/
+
+// Display attributes
+ostream & operator<<(ostream & os, const Attributes & data) {
+ os << data.GetAttributes();
+ return os;
+} // operator<<()
\ No newline at end of file
diff --git a/attributes.h b/attributes.h
index 34cf258..0ae4487 100644
--- a/attributes.h
+++ b/attributes.h
@@ -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
diff --git a/current.spec b/current.spec
index 6aed76f..650c167 100644
--- a/current.spec
+++ b/current.spec
@@ -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 @@
%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
diff --git a/gdisk.8 b/gdisk.8
index cab2654..7409f68 100644
--- a/gdisk.8
+++ b/gdisk.8
@@ -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 @@
\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
diff --git a/gpt.cc b/gpt.cc
index be3373d..3c9b843 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -58,7 +58,7 @@
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 @@
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 @@
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 @@
} // 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 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
} // 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 @@
// 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 @@
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()
diff --git a/gpt.h b/gpt.h
index d23801f..9820cae 100644
--- a/gpt.h
+++ b/gpt.h
@@ -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 @@
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;
diff --git a/gptpart.cc b/gptpart.cc
index 7be3740..2af5db7 100644
--- a/gptpart.cc
+++ b/gptpart.cc
@@ -150,7 +150,7 @@
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 @@
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 @@
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);
diff --git a/gptpart.h b/gptpart.h
index 7ed6702..25da6df 100644
--- a/gptpart.h
+++ b/gptpart.h
@@ -21,6 +21,7 @@
#include "support.h"
#include "parttypes.h"
#include "guid.h"
+#include "attributes.h"
using namespace std;
@@ -43,7 +44,8 @@
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 @@
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 @@
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);
diff --git a/gpttext.cc b/gpttext.cc
index b9039d3..69c2a6c 100644
--- a/gpttext.cc
+++ b/gpttext.cc
@@ -207,9 +207,9 @@
// 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(§or)) {
@@ -225,9 +225,9 @@
// 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 @@
// 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
diff --git a/guid.cc b/guid.cc
index 63aca2f..8e4d7dd 100644
--- a/guid.cc
+++ b/guid.cc
@@ -202,7 +202,7 @@
// Display a GUID as a string....
ostream & operator<<(ostream & os, const GUIDData & data) {
- string asString;
+// string asString;
os << data.AsString();
return os;
diff --git a/mbr.cc b/mbr.cc
index e0e92a3..782fd81 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -444,7 +444,7 @@
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
diff --git a/partnotes.cc b/partnotes.cc
index 1edd5b8..bbb38f3 100644
--- a/partnotes.cc
+++ b/partnotes.cc
@@ -600,8 +600,8 @@
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 << " ";
diff --git a/parttypes.cc b/parttypes.cc
index 37f47a7..d8d8624 100644
--- a/parttypes.cc
+++ b/parttypes.cc
@@ -192,13 +192,16 @@
// 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
diff --git a/sgdisk.8 b/sgdisk.8
index e44079b..2a9560e 100644
--- a/sgdisk.8
+++ b/sgdisk.8
@@ -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 @@
.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
diff --git a/sgdisk.cc b/sgdisk.cc
index 7b88f71..b0959a5 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -136,20 +136,26 @@
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':
diff --git a/support.cc b/support.cc
index 7db2f06..6211fdb 100644
--- a/support.cc
+++ b/support.cc
@@ -41,8 +41,7 @@
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 @@
} 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 @@
// 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 @@
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 @@
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 @@
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)
diff --git a/support.h b/support.h
index be55294..3ae2d9f 100644
--- a/support.h
+++ b/support.h
@@ -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 @@
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