From 0873e9d0e9345a2c4418b4718db525c9f1111c83 Mon Sep 17 00:00:00 2001 From: srs5694 Date: Thu, 7 Oct 2010 13:00:45 -0400 Subject: [PATCH] Version 0.6.12 release; mostly changes in support for disks with other than 512-byte sectors. --- NEWS | 23 ++++++++++++ attributes.cc | 91 ++++++++++++++++++++++++++++++--------------- attributes.h | 22 ++++++----- current.spec | 8 ++-- gdisk.8 | 21 ++++++----- gpt.cc | 76 +++++++++++++++++++------------------- gpt.h | 11 +++--- gptpart.cc | 10 ++--- gptpart.h | 8 +++- gpttext.cc | 16 ++++---- guid.cc | 2 +- mbr.cc | 2 +- partnotes.cc | 4 +- parttypes.cc | 9 +++-- sgdisk.8 | 14 +++---- sgdisk.cc | 34 ++++++++++------- support.cc | 100 +++++++++++++++++++++++++++++++++++--------------- support.h | 6 +-- 18 files changed, 286 insertions(+), 171 deletions(-) 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 @@ 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 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<<() \ 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 @@ rm -rf $RPM_BUILD_ROOT %doc %{_mandir}/man8* %changelog -* Sat Sep 25 2010 R Smith - 0.6.11 -- Created spec file for 0.6.11 release +* Thu Oct 7 2010 R Smith - 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 @@ 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 diff --git a/gpt.cc b/gpt.cc index be3373d..3c9b843 100644 --- a/gpt.cc +++ b/gpt.cc @@ -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)<= 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() 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 @@ 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; diff --git a/gptpart.cc b/gptpart.cc index 7be3740..2af5db7 100644 --- a/gptpart.cc +++ b/gptpart.cc @@ -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); 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 @@ 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); diff --git a/gpttext.cc b/gpttext.cc index b9039d3..69c2a6c 100644 --- a/gpttext.cc +++ b/gpttext.cc @@ -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(§or)) { @@ -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 diff --git a/guid.cc b/guid.cc index 63aca2f..8e4d7dd 100644 --- a/guid.cc +++ b/guid.cc @@ -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; diff --git a/mbr.cc b/mbr.cc index e0e92a3..782fd81 100644 --- a/mbr.cc +++ b/mbr.cc @@ -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 diff --git a/partnotes.cc b/partnotes.cc index 1edd5b8..bbb38f3 100644 --- a/partnotes.cc +++ b/partnotes.cc @@ -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 << " "; diff --git a/parttypes.cc b/parttypes.cc index 37f47a7..d8d8624 100644 --- a/parttypes.cc +++ b/parttypes.cc @@ -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 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 @@ 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 diff --git a/sgdisk.cc b/sgdisk.cc index 7b88f71..b0959a5 100644 --- a/sgdisk.cc +++ b/sgdisk.cc @@ -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': diff --git a/support.cc b/support.cc index 7db2f06..6211fdb 100644 --- a/support.cc +++ b/support.cc @@ -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) 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 -//#include #include #include @@ -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