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): 0.6.11 (9/25/2010):
------------------- -------------------

View File

@@ -19,11 +19,33 @@
using namespace std; using namespace std;
string Attributes::atNames[NUM_ATR]; 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; ostringstream temp;
// Most bits are undefined, so start by giving them an // Most bits are undefined, so start by giving them an
// appropriate name // appropriate name
for (int i = 0; i < NUM_ATR; i++) { for (int i = 0; i < NUM_ATR; i++) {
@@ -33,17 +55,13 @@ Attributes::staticInit::staticInit (void) {
} // for } // for
// Now reset those names that are defined.... // Now reset those names that are defined....
Attributes::atNames[0] = "system partition"; // required for computer to operate atNames[0] = "system partition"; // required for computer to operate
Attributes::atNames[1] = "hide from EFI"; atNames[1] = "hide from EFI";
Attributes::atNames[2] = "legacy BIOS bootable"; atNames[2] = "legacy BIOS bootable";
Attributes::atNames[60] = "read-only"; atNames[60] = "read-only";
Attributes::atNames[62] = "hidden"; atNames[62] = "hidden";
Attributes::atNames[63] = "do not automount"; atNames[63] = "do not automount";
} // Attributes::staticInit::staticInit } // Attributes::Setup()
// Destructor.
Attributes::~Attributes(void) {
} // Attributes destructor
// Display current attributes to user // Display current attributes to user
void Attributes::DisplayAttributes(void) { void Attributes::DisplayAttributes(void) {
@@ -57,7 +75,7 @@ void Attributes::DisplayAttributes(void) {
cout << hex << attributes << dec << ". Set fields are:\n"; cout << hex << attributes << dec << ". Set fields are:\n";
for (i = 0; i < NUM_ATR; i++) { for (i = 0; i < NUM_ATR; i++) {
if ((UINT64_C(1) << i) & attributes) { if ((UINT64_C(1) << i) & attributes) {
cout << i << " (" << Attributes::GetAttributeName(i) << ")" << "\n"; cout << i << " (" << GetAttributeName(i) << ")" << "\n";
numSet++; numSet++;
} // if } // if
} // for } // for
@@ -67,6 +85,21 @@ void Attributes::DisplayAttributes(void) {
cout << "\n"; cout << "\n";
} // Attributes::DisplayAttributes() } // 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 // Prompt user for attribute changes
void Attributes::ChangeAttributes(void) { void Attributes::ChangeAttributes(void) {
int response; int response;
@@ -78,7 +111,8 @@ void Attributes::ChangeAttributes(void) {
do { do {
DisplayAttributes(); 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) { if (response != 64) {
bitValue = UINT64_C(1) << response; // Find the integer value of the bit bitValue = UINT64_C(1) << response; // Find the integer value of the bit
if (bitValue & attributes) { // bit is set if (bitValue & attributes) { // bit is set
@@ -104,19 +138,6 @@ void Attributes::ListAttributes(void) {
} // for } // for
} // Attributes::ListAttributes } // 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 // multifaceted attributes access
// returns true upon success, false upon failure // returns true upon success, false upon failure
bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) { 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; return true;
} // Attributes::OperateOnAttributes() } // 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; using namespace std;
class Attributes { class Attributes {
private:
class staticInit {public: staticInit (void);};
static string atNames[NUM_ATR];
static Attributes::staticInit staticInitializer;
protected: protected:
static string atNames[NUM_ATR];
static int numAttrs;
void Setup(void);
uint64_t attributes; uint64_t attributes;
public: public:
Attributes(const uint64_t a = 0) {SetAttributes (a);} Attributes(void);
Attributes(const uint64_t a);
~Attributes(void); ~Attributes(void);
void SetAttributes(const uint64_t a) {attributes = a;} void operator=(uint64_t a) {attributes = a;}
uint64_t GetAttributes(void) {return attributes;}
uint64_t GetAttributes(void) const {return attributes;}
void DisplayAttributes(void); void DisplayAttributes(void);
void ChangeAttributes(void);
void ShowAttributes(const uint32_t partNum); void ShowAttributes(const uint32_t partNum);
void ChangeAttributes(void);
bool OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits); bool OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits);
static const string& GetAttributeName(const uint32_t bitNum) {return atNames [bitNum];} static const string& GetAttributeName(const uint32_t bitNum) {return atNames [bitNum];}
static void ListAttributes(void); static void ListAttributes(void);
}; // class Attributes }; // class Attributes
ostream & operator<<(ostream & os, const Attributes & data);
#endif #endif

View File

@@ -1,11 +1,11 @@
Summary: An fdisk-like partitioning tool for GPT disks Summary: An fdisk-like partitioning tool for GPT disks
Name: gdisk Name: gdisk
Version: 0.6.11 Version: 0.6.12
Release: 1%{?dist} Release: 1%{?dist}
License: GPLv2 License: GPLv2
URL: http://www.rodsbooks.com/gdisk URL: http://www.rodsbooks.com/gdisk
Group: Applications/System 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) BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%description %description
@@ -40,5 +40,5 @@ rm -rf $RPM_BUILD_ROOT
%doc %{_mandir}/man8* %doc %{_mandir}/man8*
%changelog %changelog
* Sat Sep 25 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.11 * Thu Oct 7 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.12
- Created spec file for 0.6.11 release - 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) .\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License .\" 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" .SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS" .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 \fBfdisk\fR option, although some differences exist. You enter a partition
number, starting sector, and an ending sector. Both start and end sectors number, starting sector, and an ending sector. Both start and end sectors
can be specified in absolute terms as sector numbers or as positions can be specified in absolute terms as sector numbers or as positions
measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T); measured in kibibytes (K), mebibytes (M), gibibytes (G), tebibytes (T), or
for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of pebibytes (P); for instance, \fI\fB40M\fR\fR specifies a position 40MiB
the disk. You can specify locations relative to the start or end of the from the start of the disk. You can specify locations relative to the start
specified default range by preceding the number by a '+' or '\-' symbol, as or end of the specified default range by preceding the number by a '+' or
in \fI\fB+2G\fR\fR to specify a point 2GiB after the default start sector, '\-' symbol, as in \fI\fB+2G\fR\fR to specify a point 2GiB after the
or \fI\fB\-200M\fR\fR to specify a point 200MiB before the last available default start sector, or \fI\fB\-200M\fR\fR to specify a point 200MiB
sector. Pressing the Enter key with no input specifies the default value, before the last available sector. Pressing the Enter key with no input
which is the start of the largest available block for the start sector and specifies the default value, which is the start of the largest available
the end of the same block for the end sector. block for the start sector and the end of the same block for the end
sector.
.TP .TP
.B o .B o

76
gpt.cc
View File

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

11
gpt.h
View File

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

View File

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

View File

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

View File

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

2
mbr.cc
View File

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

View File

@@ -600,8 +600,8 @@ void PartNotes::ShowSummary(void) {
cout << " * "; cout << " * ";
else else
cout << " "; cout << " ";
sizeInSI = BytesToSI(blockSize * (gptParts[theNote->gptPartNum].GetLastLBA() - sizeInSI = BytesToSI((gptParts[theNote->gptPartNum].GetLastLBA() -
gptParts[theNote->gptPartNum].GetFirstLBA() + 1)); gptParts[theNote->gptPartNum].GetFirstLBA() + 1), blockSize);
cout << " " << sizeInSI; cout << " " << sizeInSI;
for (j = 0; j < 12 - (int) sizeInSI.length(); j++) for (j = 0; j < 12 - (int) sizeInSI.length(); j++)
cout << " "; 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, // Assignment operator by string. If the original string is short,
// interpret it as a gdisk hex code; if it's longer, interpret it as // 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) { PartType & PartType::operator=(const string & orig) {
uint32_t hexCode; uint32_t hexCode;
if (orig.length() < 32) { if (orig.length() < 32) {
sscanf(orig.c_str(), "%x", &hexCode); if (IsHex(orig)) {
*this = hexCode; sscanf(orig.c_str(), "%x", &hexCode);
*this = hexCode;
} // if
} else { } else {
GUIDData::operator=(orig); GUIDData::operator=(orig);
} // if/else hexCode or GUID } // if/else hexCode or GUID

View File

@@ -1,6 +1,6 @@
.\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com) .\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License .\" 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" .SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS" .SH "SYNOPSIS"
@@ -314,12 +314,12 @@ convert partitions that start above the 2TiB mark or that are larger than
.TP .TP
.B \-n, \-\-new=partnum:start:end .B \-n, \-\-new=partnum:start:end
Create a new partition. You enter a partition Create a new partition. You enter a partition number, starting sector, and
number, starting sector, and an ending sector. Both start and end sectors an ending sector. Both start and end sectors can be specified in absolute
can be specified in absolute terms as sector numbers or as positions terms as sector numbers or as positions measured in kibibytes (K),
measured in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T); mebibytes (M), gibibytes (G), tebibytes (T), or pebibytes (P); for
for instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of instance, \fI\fB40M\fR\fR specifies a position 40MiB from the start of the
the disk. You can specify locations relative to the start or end 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 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, 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 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': { case 'A': {
if (cmd != "list") { if (cmd != "list") {
partNum = (int) GetInt(attributeOperation, 1) - 1; partNum = (int) GetInt(attributeOperation, 1) - 1;
switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2), if ((partNum >= 0) && (partNum < (int) theGPT.GetNumParts())) {
GetString(attributeOperation, 3))) { switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2),
case -1: GetString(attributeOperation, 3))) {
saveData = 0; case -1:
neverSaveData = 1; saveData = 0;
break; neverSaveData = 1;
case 1: break;
theGPT.JustLooking(0); case 1:
saveData = 1; theGPT.JustLooking(0);
break; saveData = 1;
default: break;
break; default:
} // switch break;
} // if } // switch
} else {
cerr << "Error: Invalid partition number " << partNum + 1 << "\n";
saveData = 0;
neverSaveData = 1;
} // if/else reasonable partition #
} // if (cmd != "list")
break; break;
} // case 'A': } // case 'A':
case 'a': case 'a':

View File

@@ -41,8 +41,7 @@ int GetNumber(int low, int high, int def, const string & prompt) {
char line[255]; char line[255];
if (low != high) { // bother only if low and high differ... if (low != high) { // bother only if low and high differ...
response = low - 1; // force one loop by setting response outside range do {
while ((response < low) || (response > high)) {
cout << prompt; cout << prompt;
cin.getline(line, 255); cin.getline(line, 255);
num = sscanf(line, "%d", &response); 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 } else { // user hit enter; return default
response = def; response = def;
} // if/else } // if/else
} // while } while ((response < low) || (response > high));
} else { // low == high, so return this value } else { // low == high, so return this value
cout << "Using " << low << "\n"; cout << "Using " << low << "\n";
response = low; 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) // Gets a Y/N response (and converts lowercase to uppercase)
char GetYN(void) { char GetYN(void) {
char line[255]; char line[255];
char response = '\0'; char response;
char *junk; char *junk;
while ((response != 'Y') && (response != 'N')) { do {
cout << "(Y/N): "; cout << "(Y/N): ";
junk = fgets(line, 255, stdin); junk = fgets(line, 255, stdin);
sscanf(line, "%c", &response); sscanf(line, "%c", &response);
if (response == 'y') response = 'Y'; if (response == 'y')
if (response == 'n') response = 'N'; response = 'Y';
} // while if (response == 'n')
response = 'N';
} while ((response != 'Y') && (response != 'N'));
return response; return response;
} // GetYN(void) } // GetYN(void)
// Obtains a sector number, between low and high, from the // Obtains a sector number, between low and high, from the
// user, accepting values prefixed by "+" to add sectors to low, // user, accepting values prefixed by "+" to add sectors to low,
// or the same with "K", "M", "G", or "T" as suffixes to add // or the same with "K", "M", "G", "T", or "P" as suffixes to add
// kilobytes, megabytes, gigabytes, or terabytes, respectively. // kilobytes, megabytes, gigabytes, terabytes, or petabytes,
// If a "-" prefix is used, use the high value minus the user- // respectively. If a "-" prefix is used, use the high value minus
// specified number of sectors (or KiB, MiB, etc.). Use the def // the user-specified number of sectors (or KiB, MiB, etc.). Use the
//value as the default if the user just hits Enter // def value as the default if the user just hits Enter. The sSize is
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt) { // the sector size of the device.
uint64_t response, mult = 1; 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; int plusFlag = 0;
char suffix, line[255]; char suffix, line[255];
response = low - 1; // Ensure one pass by setting a too-low initial value if (sSize == 0) {
while ((response < low) || (response > high)) { sSize = SECTOR_SIZE;
cerr << "Bug: Sector size invalid in GetSectorNum()!\n";
} // if
do {
cout << prompt; cout << prompt;
cin.getline(line, 255); cin.getline(line, 255);
@@ -124,26 +130,36 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string &
switch (suffix) { switch (suffix) {
case 'K': case 'K':
case 'k': case 'k':
mult = (uint64_t) 1024 / SECTOR_SIZE; mult = UINT64_C(1024) / sSize;
divide = sSize / UINT64_C(1024);
break;
break; break;
case 'M': case 'M':
case 'm': case 'm':
mult = (uint64_t) 1048576 / SECTOR_SIZE; mult = UINT64_C(1048576) / sSize;
divide = sSize / UINT64_C(1048576);
break; break;
case 'G': case 'G':
case 'g': case 'g':
mult = (uint64_t) 1073741824 / SECTOR_SIZE; mult = UINT64_C(1073741824) / sSize;
break; break;
case 'T': case 'T':
case 't': case 't':
mult = ((uint64_t) 1073741824 * (uint64_t) 1024) / (uint64_t) SECTOR_SIZE; mult = UINT64_C(1099511627776) / sSize;
break;
case 'P':
case 'p':
mult = UINT64_C(1125899906842624) / sSize;
break; break;
default: default:
mult = 1; mult = 1;
} // switch } // switch
// Adjust response based on multiplier and plus flag, if present // 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) { if (plusFlag == 1) {
// Recompute response based on low part of range (if default = high // Recompute response based on low part of range (if default = high
// value, which should be the case when prompting for the end of a // 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) { if (plusFlag == -1) {
response = high - response; response = high - response;
} // if } // if
} // while } while ((response < low) || (response > high));
return response; return response;
} // GetSectorNum() } // GetSectorNum()
// Takes a size in bytes (in size) and converts this to a size in // Takes a size and converts this to a size in SI units (KiB, MiB, GiB,
// SI units (KiB, MiB, GiB, TiB, or PiB), returned in C++ string // TiB, or PiB), returned in C++ string form. The size is either in units
// form // of the sector size or, if that parameter is omitted, in bytes.
string BytesToSI(uint64_t size) { // (sectorSize defaults to 1).
string BytesToSI(uint64_t size, uint32_t sectorSize) {
string units; string units;
ostringstream theValue; ostringstream theValue;
float sizeInSI; float sizeInSI;
sizeInSI = (float) size; sizeInSI = (float) size * (float) sectorSize;
units = " bytes"; units = " bytes";
if (sizeInSI > 1024.0) { if (sizeInSI > 1024.0) {
sizeInSI /= 1024.0; sizeInSI /= 1024.0;
@@ -215,6 +232,29 @@ unsigned char StrToHex(const string & input, unsigned int position) {
return retval; return retval;
} // StrToHex() } // 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.... // Return 1 if the CPU architecture is little endian, 0 if it's big endian....
int IsLittleEndian(void) { int IsLittleEndian(void) {
int littleE = 1; // assume little-endian (Intel-style) 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. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h> #include <stdint.h>
//#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
@@ -50,9 +49,10 @@ using namespace std;
int GetNumber(int low, int high, int def, const string & prompt); int GetNumber(int low, int high, int def, const string & prompt);
char GetYN(void); char GetYN(void);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt); uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
string BytesToSI(uint64_t size); string BytesToSI(uint64_t size, uint32_t sectorSize = 1);
unsigned char StrToHex(const string & input, unsigned int position); 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 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 void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue