Version 0.6.12 release; mostly changes in support for disks with other
than 512-byte sectors.
This commit is contained in:
23
NEWS
23
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):
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -19,9 +19,31 @@
|
||||
using namespace std;
|
||||
|
||||
string Attributes::atNames[NUM_ATR];
|
||||
Attributes::staticInit Attributes::staticInitializer;
|
||||
int Attributes::numAttrs = 0;
|
||||
//Attributes::staticInit Attributes::staticInitializer;
|
||||
|
||||
Attributes::staticInit::staticInit (void) {
|
||||
// Default constructor
|
||||
Attributes::Attributes(void) {
|
||||
numAttrs++;
|
||||
if (numAttrs == 1)
|
||||
Setup();
|
||||
attributes = 0;
|
||||
} // constructor
|
||||
|
||||
// Alternate constructor
|
||||
Attributes::Attributes(const uint64_t a) {
|
||||
numAttrs++;
|
||||
if (numAttrs == 1)
|
||||
Setup();
|
||||
attributes = a;
|
||||
} // alternate constructor
|
||||
|
||||
// Destructor.
|
||||
Attributes::~Attributes(void) {
|
||||
numAttrs--;
|
||||
} // Attributes destructor
|
||||
|
||||
void Attributes::Setup(void) {
|
||||
ostringstream temp;
|
||||
|
||||
// Most bits are undefined, so start by giving them an
|
||||
@@ -33,17 +55,13 @@ Attributes::staticInit::staticInit (void) {
|
||||
} // for
|
||||
|
||||
// Now reset those names that are defined....
|
||||
Attributes::atNames[0] = "system partition"; // required for computer to operate
|
||||
Attributes::atNames[1] = "hide from EFI";
|
||||
Attributes::atNames[2] = "legacy BIOS bootable";
|
||||
Attributes::atNames[60] = "read-only";
|
||||
Attributes::atNames[62] = "hidden";
|
||||
Attributes::atNames[63] = "do not automount";
|
||||
} // Attributes::staticInit::staticInit
|
||||
|
||||
// Destructor.
|
||||
Attributes::~Attributes(void) {
|
||||
} // Attributes destructor
|
||||
atNames[0] = "system partition"; // required for computer to operate
|
||||
atNames[1] = "hide from EFI";
|
||||
atNames[2] = "legacy BIOS bootable";
|
||||
atNames[60] = "read-only";
|
||||
atNames[62] = "hidden";
|
||||
atNames[63] = "do not automount";
|
||||
} // Attributes::Setup()
|
||||
|
||||
// Display current attributes to user
|
||||
void Attributes::DisplayAttributes(void) {
|
||||
@@ -57,7 +75,7 @@ void Attributes::DisplayAttributes(void) {
|
||||
cout << hex << attributes << dec << ". Set fields are:\n";
|
||||
for (i = 0; i < NUM_ATR; i++) {
|
||||
if ((UINT64_C(1) << i) & attributes) {
|
||||
cout << i << " (" << Attributes::GetAttributeName(i) << ")" << "\n";
|
||||
cout << i << " (" << GetAttributeName(i) << ")" << "\n";
|
||||
numSet++;
|
||||
} // if
|
||||
} // for
|
||||
@@ -67,6 +85,21 @@ void Attributes::DisplayAttributes(void) {
|
||||
cout << "\n";
|
||||
} // Attributes::DisplayAttributes()
|
||||
|
||||
// Display attributes for a partition. Note that partNum is just passed for
|
||||
// immediate display; it's not used to access a particular partition.
|
||||
void Attributes::ShowAttributes(const uint32_t partNum) {
|
||||
uint32_t bitNum;
|
||||
bool bitset;
|
||||
|
||||
for (bitNum = 0; bitNum < 64; bitNum++) {
|
||||
bitset = (UINT64_C(1) << bitNum) & attributes;
|
||||
if (bitset) {
|
||||
cout << partNum+1 << ":" << bitNum << ":" << bitset
|
||||
<< " (" << GetAttributeName(bitNum) << ")" << endl;
|
||||
} // if
|
||||
} // for
|
||||
} // Attributes::ShowAttributes
|
||||
|
||||
// Prompt user for attribute changes
|
||||
void Attributes::ChangeAttributes(void) {
|
||||
int response;
|
||||
@@ -78,7 +111,8 @@ void Attributes::ChangeAttributes(void) {
|
||||
|
||||
do {
|
||||
DisplayAttributes();
|
||||
response = GetNumber(0, NUM_ATR, -1, "Toggle which attribute field (0-63, 64 to exit): ");
|
||||
response = GetNumber(0, NUM_ATR, 64,
|
||||
"Toggle which attribute field (0-63, 64 or <Enter> to exit): ");
|
||||
if (response != 64) {
|
||||
bitValue = UINT64_C(1) << response; // Find the integer value of the bit
|
||||
if (bitValue & attributes) { // bit is set
|
||||
@@ -104,19 +138,6 @@ void Attributes::ListAttributes(void) {
|
||||
} // for
|
||||
} // Attributes::ListAttributes
|
||||
|
||||
void Attributes::ShowAttributes(const uint32_t partNum) {
|
||||
uint32_t bitNum;
|
||||
bool bitset;
|
||||
|
||||
for (bitNum = 0; bitNum < 64; bitNum++) {
|
||||
bitset = (UINT64_C(1) << bitNum) & attributes;
|
||||
if (bitset) {
|
||||
cout << partNum+1 << ":" << bitNum << ":" << bitset
|
||||
<< " (" << Attributes::GetAttributeName(bitNum) << ")" << endl;
|
||||
} // if
|
||||
} // for
|
||||
} // Attributes::ShowAttributes
|
||||
|
||||
// multifaceted attributes access
|
||||
// returns true upon success, false upon failure
|
||||
bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) {
|
||||
@@ -190,3 +211,15 @@ bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attri
|
||||
|
||||
return true;
|
||||
} // Attributes::OperateOnAttributes()
|
||||
|
||||
/*******************************
|
||||
* *
|
||||
* Non-class support functions *
|
||||
* *
|
||||
*******************************/
|
||||
|
||||
// Display attributes
|
||||
ostream & operator<<(ostream & os, const Attributes & data) {
|
||||
os << data.GetAttributes();
|
||||
return os;
|
||||
} // operator<<()
|
||||
22
attributes.h
22
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
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Summary: An fdisk-like partitioning tool for GPT disks
|
||||
Name: gdisk
|
||||
Version: 0.6.11
|
||||
Version: 0.6.12
|
||||
Release: 1%{?dist}
|
||||
License: GPLv2
|
||||
URL: http://www.rodsbooks.com/gdisk
|
||||
Group: Applications/System
|
||||
Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.11.tgz
|
||||
Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.12.tgz
|
||||
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
|
||||
|
||||
%description
|
||||
@@ -40,5 +40,5 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%doc %{_mandir}/man8*
|
||||
|
||||
%changelog
|
||||
* Sat Sep 25 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.11
|
||||
- Created spec file for 0.6.11 release
|
||||
* Thu Oct 7 2010 R Smith <rodsmith@rodsbooks.com> - 0.6.12
|
||||
- Created spec file for 0.6.12 release
|
||||
|
||||
21
gdisk.8
21
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
|
||||
|
||||
76
gpt.cc
76
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)<<exponent;
|
||||
align = UINT64_C(1) << exponent;
|
||||
if ((partitions[i].GetFirstLBA() % align) == 0) {
|
||||
found = 1;
|
||||
} else {
|
||||
@@ -2207,9 +2211,9 @@ uint32_t GPTData::ComputeAlignment(void) {
|
||||
} // while
|
||||
} // if
|
||||
} // for
|
||||
if ((align < 8) && (diskSize >= SMALLEST_ADVANCED_FORMAT))
|
||||
align = 8;
|
||||
SetAlignment(align);
|
||||
if ((align < MIN_AF_ALIGNMENT) && (diskSize >= SMALLEST_ADVANCED_FORMAT))
|
||||
align = MIN_AF_ALIGNMENT;
|
||||
sectorAlignment = align;
|
||||
return align;
|
||||
} // GPTData::ComputeAlignment()
|
||||
|
||||
@@ -2296,14 +2300,12 @@ int GPTData::ManageAttributes(int partNum, const string & command, const string
|
||||
|
||||
// Show all attributes for a specified partition....
|
||||
void GPTData::ShowAttributes(const uint32_t partNum) {
|
||||
Attributes theAttr (partitions[partNum].GetAttributes());
|
||||
theAttr.ShowAttributes(partNum);
|
||||
partitions[partNum].ShowAttributes(partNum);
|
||||
} // GPTData::ShowAttributes
|
||||
|
||||
// Show whether a single attribute bit is set (terse output)...
|
||||
void GPTData::GetAttribute(const uint32_t partNum, const string& attributeBits) {
|
||||
Attributes theAttr (partitions[partNum].GetAttributes());
|
||||
theAttr.OperateOnAttributes(partNum, "get", attributeBits);
|
||||
partitions[partNum].GetAttributes().OperateOnAttributes(partNum, "get", attributeBits);
|
||||
} // GPTData::GetAttribute
|
||||
|
||||
|
||||
@@ -2361,10 +2363,10 @@ int SizesOK(void) {
|
||||
allOK = 0;
|
||||
} // if
|
||||
// Determine endianness; warn user if running on big-endian (PowerPC, etc.) hardware
|
||||
if (IsLittleEndian() == 0) {
|
||||
cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"
|
||||
" tested!\n";
|
||||
} // if
|
||||
// if (IsLittleEndian() == 0) {
|
||||
// cerr << "\aRunning on big-endian hardware. Big-endian support is new and poorly"
|
||||
// " tested!\n";
|
||||
// } // if
|
||||
return (allOK);
|
||||
} // SizesOK()
|
||||
|
||||
|
||||
11
gpt.h
11
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;
|
||||
|
||||
|
||||
10
gptpart.cc
10
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
16
gpttext.cc
16
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
|
||||
|
||||
2
guid.cc
2
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;
|
||||
|
||||
2
mbr.cc
2
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
|
||||
|
||||
@@ -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 << " ";
|
||||
|
||||
@@ -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
|
||||
|
||||
14
sgdisk.8
14
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
|
||||
|
||||
34
sgdisk.cc
34
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':
|
||||
|
||||
100
support.cc
100
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)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
||||
|
||||
#include <stdint.h>
|
||||
//#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
|
||||
@@ -50,9 +49,10 @@ using namespace std;
|
||||
|
||||
int GetNumber(int low, int high, int def, const string & prompt);
|
||||
char GetYN(void);
|
||||
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string & prompt);
|
||||
string BytesToSI(uint64_t size);
|
||||
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
|
||||
string BytesToSI(uint64_t size, uint32_t sectorSize = 1);
|
||||
unsigned char StrToHex(const string & input, unsigned int position);
|
||||
int IsHex(const string & input); // Returns 1 if input can be hexadecimal number....
|
||||
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
|
||||
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user