sgdisk program, misc. bug fixes
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
0.6.0 (1/??/2009):
|
||||
------------------
|
||||
|
||||
- Fixed bug that caused the convert to MBR function to fail.
|
||||
|
||||
- Added support for disks with other than 512-byte sectors.
|
||||
|
||||
- Created embryonic sgdisk program.
|
||||
|
||||
- Fixed bug that caused relative sector numbers entered by users (e.g,
|
||||
"+128M") to be misinterpreted as from the start of the range rather than
|
||||
from the default value.
|
||||
|
||||
0.5.3 (1/4/2009):
|
||||
-----------------
|
||||
|
||||
|
||||
11
Makefile
11
Makefile
@@ -1,8 +1,7 @@
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
#CFLAGS=-O2 -fpack-struct
|
||||
CFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
|
||||
CXXFLAGS=-O2 -fpack-struct -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -g
|
||||
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
|
||||
CXXFLAGS=-O2 -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I/opt/local/include -g
|
||||
LIB_NAMES=crc32 support gptpart mbr gpt bsd parttypes attributes
|
||||
LIB_SRCS=$(NAMES:=.cc)
|
||||
LIB_OBJS=$(LIB_NAMES:=.o)
|
||||
@@ -12,11 +11,13 @@ DEPEND= makedepend $(CFLAGS)
|
||||
#$(APPNAME): $(MBR2GPT_OBJS)
|
||||
# $(CC) $(MBR2GPT_OBJS) -o $@
|
||||
|
||||
all: gdisk sgdisk
|
||||
|
||||
gdisk: $(LIB_OBJS) gdisk.o
|
||||
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk
|
||||
|
||||
sgdisk: $(LIB_OBJS) sgdisk.o
|
||||
$(CXX) $(LIB_OBJS) sgdisk.o -o sgdisk
|
||||
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -lpopt -o sgdisk
|
||||
|
||||
wipegpt: $(LIB_OBJS) wipegpt.o
|
||||
$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
|
||||
@@ -25,7 +26,7 @@ lint: #no pre-reqs
|
||||
lint $(SRCS)
|
||||
|
||||
clean: #no pre-reqs
|
||||
rm -f core *.o *~ gdisk
|
||||
rm -f core *.o *~ gdisk sgdisk
|
||||
|
||||
# what are the source dependencies
|
||||
depend: $(SRCS)
|
||||
|
||||
21
README
21
README
@@ -44,11 +44,22 @@ Installing
|
||||
|
||||
To compile gdisk, you must have appropriate development tools installed,
|
||||
most notably the GNU Compiler Collection (GCC) and its g++ compiler for
|
||||
C++. Uncompress the package and type "make" at the command prompt in the
|
||||
resulting directory. The result should be a program file called gdisk. You
|
||||
can use this in place or copy the file to a suitable directory, such as
|
||||
/usr/local/sbin. You can copy the man page (gdisk.8) to /usr/local/man/man8
|
||||
to make it available.
|
||||
C++. The sgdisk program also requires the popt library and its development
|
||||
files (headers). Most Linux distributions install popt by default, but you
|
||||
may need to install a package called popt-dev, popt-devel, or something
|
||||
similar to obtain the development libraries. Mac OS users can find a version
|
||||
of popt for Mac OS from http://popt.darwinports.com; however, you'll first
|
||||
need to install DarwinPorts (instructions exist on the preceding page).
|
||||
Alternatively, you can compile gdisk alone, without sgdisk; gdisk doesn't
|
||||
require popt.
|
||||
|
||||
When all the necessary development tools and libraries are installed, you
|
||||
can uncompress the package and type "make" at the command prompt in the
|
||||
resulting directory. The result should be program files called gdisk and
|
||||
sgdisk. Typing "make gdisk" or "make sgdisk" will compile only the requested
|
||||
programs. You can use these programs in place or copy the files to a
|
||||
suitable directory, such as /usr/local/sbin. You can copy the man pages
|
||||
(gdisk.8 and sgdisk.8) to /usr/local/man/man8 to make them available.
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
37
bsd.cc
37
bsd.cc
@@ -70,12 +70,15 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
|
||||
uint32_t* temp32;
|
||||
uint16_t* temp16;
|
||||
BSDRecord* tempRecords;
|
||||
int offset[3] = { LABEL_OFFSET1, LABEL_OFFSET2, LABEL_OFFSET3 };
|
||||
|
||||
labelFirstLBA = startSector;
|
||||
labelLastLBA = endSector;
|
||||
|
||||
// Read eight sectors into memory; we'll extract data from
|
||||
// this buffer. (Done to work around FreeBSD limitation)
|
||||
// Read 4096 bytes (eight 512-byte sectors or equivalent)
|
||||
// into memory; we'll extract data from this buffer.
|
||||
// (Done to work around FreeBSD limitation on size of reads
|
||||
// from block devices.)
|
||||
lseek64(fd, startSector * GetBlockSize(fd), SEEK_SET);
|
||||
err = read(fd, buffer, 4096);
|
||||
|
||||
@@ -85,27 +88,23 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
|
||||
if (bigEnd)
|
||||
ReverseBytes(&realSig, 4);
|
||||
|
||||
// Look for the signature at one of two locations
|
||||
labelStart = LABEL_OFFSET1;
|
||||
temp32 = (uint32_t*) &buffer[labelStart];
|
||||
signature = *temp32;
|
||||
if (signature == realSig) {
|
||||
temp32 = (uint32_t*) &buffer[labelStart + 132];
|
||||
signature2 = *temp32;
|
||||
if (signature2 == realSig)
|
||||
foundSig = 1;
|
||||
} // if/else
|
||||
if (!foundSig) { // look in second location
|
||||
labelStart = LABEL_OFFSET2;
|
||||
temp32 = (uint32_t*) &buffer[labelStart];
|
||||
// Look for the signature at any of three locations.
|
||||
// Note that the signature is repeated at both the original
|
||||
// offset and 132 bytes later, so we need two checks....
|
||||
i = 0;
|
||||
do {
|
||||
temp32 = (uint32_t*) &buffer[offset[i]];
|
||||
signature = *temp32;
|
||||
if (signature == realSig) {
|
||||
temp32 = (uint32_t*) &buffer[labelStart + 132];
|
||||
if (signature == realSig) { // found first, look for second
|
||||
temp32 = (uint32_t*) &buffer[offset[i] + 132];
|
||||
signature2 = *temp32;
|
||||
if (signature2 == realSig)
|
||||
if (signature2 == realSig) {
|
||||
foundSig = 1;
|
||||
labelStart = offset[i];
|
||||
} // if found signature
|
||||
} // if/else
|
||||
} // if
|
||||
i++;
|
||||
} while ((!foundSig) && (i < 3));
|
||||
|
||||
// Load partition metadata from the buffer....
|
||||
temp32 = (uint32_t*) &buffer[labelStart + 40];
|
||||
|
||||
12
bsd.h
12
bsd.h
@@ -13,14 +13,16 @@
|
||||
|
||||
#define BSD_SIGNATURE UINT32_C(0x82564557) /* BSD disklabel signature ("magic") */
|
||||
|
||||
#define LABEL_OFFSET1 64 /* BSD disklabels can start at one of these two */
|
||||
#define LABEL_OFFSET2 512 /* values; check both for valid signatures */
|
||||
#define LABEL_OFFSET1 64 /* BSD disklabels can start at any of these three */
|
||||
#define LABEL_OFFSET2 512 /* values; check all for valid signatures */
|
||||
#define LABEL_OFFSET3 2048
|
||||
|
||||
// FreeBSD documents a maximum # of partitions of 8, but I saw 16 on a NetBSD
|
||||
// disk. I'm quadrupling that for further safety. Note that BSDReadData()
|
||||
// uses a 2048-byte I/O buffer. In combination with LABEL_OFFSET2 and the
|
||||
// uses a 4096-byte I/O buffer. In combination with LABEL_OFFSET3 and the
|
||||
// additional 148-byte offset to the actual partition data, that gives a
|
||||
// theoretical maximum of 86.75 partitions that the program can handle.
|
||||
// theoretical maximum of 118.75 partitions that the program can handle before
|
||||
// memory errors will occur.
|
||||
#define MAX_BSD_PARTS 64
|
||||
|
||||
|
||||
@@ -47,7 +49,7 @@ struct BSDRecord { // the partition table
|
||||
uint16_t pcpg; // filesystem cylinders per group
|
||||
};
|
||||
|
||||
// Full data in tweaked MBR format
|
||||
// Full data in tweaked BSD format
|
||||
class BSDData {
|
||||
protected:
|
||||
// We only need a few items from the main BSD disklabel data structure....
|
||||
|
||||
13
gdisk.8
13
gdisk.8
@@ -2,7 +2,7 @@
|
||||
.\" May be distributed under the GNU General Public License
|
||||
.TH "GDISK" "8" "0.5.3" "Roderick W. Smith" "GPT fdisk Manual"
|
||||
.SH "NAME"
|
||||
gdisk \- GUID partition table (GPT) manipulator for Linux and Unix
|
||||
gdisk \- Interactive GUID partition table (GPT) manipulator for Linux and Unix
|
||||
.SH "SYNOPSIS"
|
||||
.BI "gdisk "
|
||||
[ \-l ]
|
||||
@@ -198,12 +198,12 @@ 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 range by preceding the number by a '+' or '\-' symbol, as in
|
||||
\fI\fB+2G\fR\fR to specify a point 2GiB after the first available sector,
|
||||
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 last available block for the end sector.
|
||||
the end of the same block for the end sector.
|
||||
|
||||
.TP
|
||||
.B o
|
||||
@@ -532,10 +532,7 @@ should be considered beta software. Known bugs and limitations include:
|
||||
.B *
|
||||
The program compiles correctly only on Linux, FreeBSD, and Mac OS X. Linux
|
||||
versions for x86\-64 (64\-bit), x86 (32\-bit), and PowerPC (32\-bit) have been
|
||||
tested, with the x86\-64 version having seen the most testing. The Mac OS X
|
||||
support was added with version 0.3.1 and has not been as thoroughly tested.
|
||||
FreeBSD support was added with version 0.4.0 and has seen even less
|
||||
testing.
|
||||
tested, with the x86\-64 version having seen the most testing.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
|
||||
10
gdisk.cc
10
gdisk.cc
@@ -170,7 +170,7 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
|
||||
int goOn = 1;
|
||||
|
||||
do {
|
||||
printf("\nrecovery/transformation command (? for help): ");
|
||||
printf("\nRecovery/transformation command (? for help): ");
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
@@ -313,7 +313,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||
} else printf("No partitions\n");
|
||||
break;
|
||||
case 'd': case 'D':
|
||||
printf("The number of logical sectors per physical sector is %d.\n",
|
||||
printf("Partitions will begin on %d-sector boundaries.\n",
|
||||
theGPT->GetAlignment());
|
||||
break;
|
||||
case 'e': case 'E':
|
||||
@@ -328,7 +328,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||
theGPT->ShowDetails();
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
temp1 = GetNumber(1, 128, 8, "Enter the number of logical sectors in a physical sector on the\ndisk (1-128, default = 8): ");
|
||||
temp1 = GetNumber(1, 128, 8, "Enter the sector alignment value (1-128, default = 8): ");
|
||||
theGPT->SetAlignment(temp1);
|
||||
break;
|
||||
case 'm': case 'M':
|
||||
@@ -377,11 +377,11 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||
void ShowExpertCommands(void) {
|
||||
printf("a\tset attributes\n");
|
||||
printf("c\tchange partition GUID\n");
|
||||
printf("d\tdisplay the number of logical sectors per physical sector\n");
|
||||
printf("d\tdisplay the sector alignment value\n");
|
||||
printf("e\trelocate backup data structures to the end of the disk\n");
|
||||
printf("g\tchange disk GUID\n");
|
||||
printf("i\tshow detailed information on a partition\n");
|
||||
printf("b\tset the number of logical sectors per physical sector\n");
|
||||
printf("l\tset the sector alignment value\n");
|
||||
printf("m\treturn to main menu\n");
|
||||
printf("n\tcreate a new protective MBR\n");
|
||||
printf("o\tprint protective MBR data\n");
|
||||
|
||||
158
gpt.cc
158
gpt.cc
@@ -48,6 +48,8 @@ GPTData::GPTData(void) {
|
||||
apmFound = 0;
|
||||
bsdFound = 0;
|
||||
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
|
||||
beQuiet = 0;
|
||||
whichWasUsed = use_new;
|
||||
srand((unsigned int) time(NULL));
|
||||
mainHeader.numParts = 0;
|
||||
SetGPTSize(NUM_GPT_ENTRIES);
|
||||
@@ -68,6 +70,8 @@ GPTData::GPTData(char* filename) {
|
||||
apmFound = 0;
|
||||
bsdFound = 0;
|
||||
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
|
||||
beQuiet = 0;
|
||||
whichWasUsed = use_new;
|
||||
srand((unsigned int) time(NULL));
|
||||
mainHeader.numParts = 0;
|
||||
LoadPartitions(filename);
|
||||
@@ -499,22 +503,22 @@ int GPTData::FindOverlaps(void) {
|
||||
// the results.
|
||||
void GPTData::PartitionScan(int fd) {
|
||||
BSDData bsdDisklabel;
|
||||
// int bsdFound;
|
||||
|
||||
printf("Partition table scan:\n");
|
||||
|
||||
// Read the MBR & check for BSD disklabel
|
||||
protectiveMBR.ReadMBRData(fd);
|
||||
protectiveMBR.ShowState();
|
||||
bsdDisklabel.ReadBSDData(fd, 0, diskSize - 1);
|
||||
bsdFound = bsdDisklabel.ShowState();
|
||||
// bsdDisklabel.DisplayBSDData();
|
||||
|
||||
// Load the GPT data, whether or not it's valid
|
||||
ForceLoadGPTData(fd);
|
||||
ShowAPMState(); // Show whether there's an Apple Partition Map present
|
||||
ShowGPTState(); // Show GPT status
|
||||
printf("\n");
|
||||
|
||||
if (!beQuiet) {
|
||||
printf("Partition table scan:\n");
|
||||
protectiveMBR.ShowState();
|
||||
bsdDisklabel.ShowState();
|
||||
ShowAPMState(); // Show whether there's an Apple Partition Map present
|
||||
ShowGPTState(); // Show GPT status
|
||||
printf("\n");
|
||||
} // if
|
||||
|
||||
if (apmFound) {
|
||||
printf("\n*******************************************************************\n");
|
||||
@@ -549,9 +553,10 @@ int GPTData::LoadPartitions(char* deviceFilename) {
|
||||
blockSize = (uint32_t) GetBlockSize(fd);
|
||||
sectorAlignment = FindAlignment(fd);
|
||||
strcpy(device, deviceFilename);
|
||||
PartitionScan(fd); // Check for partition types & print summary
|
||||
PartitionScan(fd); // Check for partition types, load GPT, & print summary
|
||||
|
||||
switch (UseWhichPartitions()) {
|
||||
whichWasUsed = UseWhichPartitions();
|
||||
switch (whichWasUsed) {
|
||||
case use_mbr:
|
||||
XFormPartitions();
|
||||
break;
|
||||
@@ -696,7 +701,7 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
(secondPartsCrcOk == 0)) {
|
||||
printf("Warning! One or more CRCs don't match. You should repair the disk!\n");
|
||||
state = gpt_corrupt;
|
||||
} // if
|
||||
} // if
|
||||
} else {
|
||||
state = gpt_invalid;
|
||||
} // if/else
|
||||
@@ -763,7 +768,7 @@ void GPTData::LoadSecondTableAsMain(void) {
|
||||
|
||||
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
|
||||
// write, 0 if there was a problem.
|
||||
int GPTData::SaveGPTData(void) {
|
||||
int GPTData::SaveGPTData(int quiet) {
|
||||
int allOK = 1;
|
||||
char answer, line[256];
|
||||
int fd;
|
||||
@@ -799,7 +804,7 @@ int GPTData::SaveGPTData(void) {
|
||||
} // if
|
||||
// Check that second header is properly placed. Warn and ask if this should
|
||||
// be corrected if the test fails....
|
||||
if (mainHeader.backupLBA < (diskSize - UINT64_C(1))) {
|
||||
if ((mainHeader.backupLBA < (diskSize - UINT64_C(1))) && (quiet == 0)) {
|
||||
printf("Warning! Secondary header is placed too early on the disk! Do you want to\n"
|
||||
"correct this problem? ");
|
||||
if (GetYN() == 'Y') {
|
||||
@@ -833,7 +838,7 @@ int GPTData::SaveGPTData(void) {
|
||||
} // if
|
||||
RecomputeCRCs();
|
||||
|
||||
if (allOK) {
|
||||
if ((allOK) && (!quiet)) {
|
||||
printf("\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n");
|
||||
printf("MBR PARTITIONS!! THIS PROGRAM IS BETA QUALITY AT BEST. IF YOU LOSE ALL YOUR\n");
|
||||
printf("DATA, YOU HAVE ONLY YOURSELF TO BLAME IF YOU ANSWER 'Y' BELOW!\n\n");
|
||||
@@ -1251,36 +1256,24 @@ void GPTData::CreatePartition(void) {
|
||||
} while (IsFree(sector) == 0);
|
||||
lastBlock = sector;
|
||||
|
||||
partitions[partNum].SetFirstLBA(firstBlock);
|
||||
partitions[partNum].SetLastLBA(lastBlock);
|
||||
|
||||
partitions[partNum].SetUniqueGUID(1);
|
||||
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
|
||||
partitions[partNum].ChangeType();
|
||||
partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType(prompt));
|
||||
} else {
|
||||
printf("No free sectors available\n");
|
||||
} // if/else
|
||||
} else {
|
||||
printf("No free sectors available\n");
|
||||
} // if/else
|
||||
} // GPTData::CreatePartition()
|
||||
|
||||
// Interactively delete a partition (duh!)
|
||||
void GPTData::DeletePartition(void) {
|
||||
int partNum;
|
||||
uint32_t low, high;
|
||||
uint64_t startSector, length;
|
||||
char prompt[255];
|
||||
|
||||
if (GetPartRange(&low, &high) > 0) {
|
||||
sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
|
||||
partNum = GetNumber(low + 1, high + 1, low, prompt);
|
||||
|
||||
// In case there's a protective MBR, look for & delete matching
|
||||
// MBR partition....
|
||||
startSector = partitions[partNum - 1].GetFirstLBA();
|
||||
length = partitions[partNum - 1].GetLengthLBA();
|
||||
protectiveMBR.DeleteByLocation(startSector, length);
|
||||
|
||||
// Now delete the GPT partition
|
||||
partitions[partNum - 1].BlankPartition();
|
||||
DeletePartition(partNum - 1);
|
||||
} else {
|
||||
printf("No partitions\n");
|
||||
} // if/else
|
||||
@@ -1315,6 +1308,8 @@ void GPTData::SetAttributes(uint32_t partNum) {
|
||||
// user confirms destruction, 0 if the user aborts.
|
||||
// If prompt == 0, don't ask user about proceeding and do NOT wipe out
|
||||
// MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.)
|
||||
// If prompt == -1, don't ask user about proceeding and DO wipe out
|
||||
// MBR.
|
||||
int GPTData::DestroyGPT(int prompt) {
|
||||
int fd, i, sum, tableSize;
|
||||
char blankSector[512], goOn = 'Y', blank = 'N';
|
||||
@@ -1324,11 +1319,11 @@ int GPTData::DestroyGPT(int prompt) {
|
||||
blankSector[i] = '\0';
|
||||
} // for
|
||||
|
||||
if (((apmFound) || (bsdFound)) && prompt) {
|
||||
if (((apmFound) || (bsdFound)) && (prompt > 0)) {
|
||||
printf("WARNING: APM or BSD disklabel structures detected! This operation could\n"
|
||||
"damage any APM or BSD partitions on this disk!\n");
|
||||
} // if APM or BSD
|
||||
if (prompt) {
|
||||
if (prompt > 0) {
|
||||
printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
|
||||
goOn = GetYN();
|
||||
} // if
|
||||
@@ -1361,16 +1356,16 @@ int GPTData::DestroyGPT(int prompt) {
|
||||
if (myWrite(fd, blankSector, 512) != 512) { // blank it out
|
||||
fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
|
||||
} // if
|
||||
if (prompt) {
|
||||
if (prompt > 0) {
|
||||
printf("Blank out MBR? ");
|
||||
blank = GetYN();
|
||||
}// if
|
||||
} // if
|
||||
// Note on below: Touch the MBR only if the user wants it completely
|
||||
// blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote
|
||||
// the MBR, but this could wipe out a valid MBR that the program
|
||||
// had subsequently discarded (say, if it conflicted with older GPT
|
||||
// structures).
|
||||
if (blank == 'Y') {
|
||||
if ((blank == 'Y') || (prompt < 0)) {
|
||||
lseek64(fd, 0, SEEK_SET);
|
||||
if (myWrite(fd, blankSector, 512) != 512) { // blank it out
|
||||
fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
|
||||
@@ -1681,6 +1676,7 @@ int GPTData::XFormToMBR(void) {
|
||||
printf("\nCreating entry for partition #%d\n", j + 1);
|
||||
numConverted += OnePartToMBR(j, i);
|
||||
} // for
|
||||
printf("MBR writing returned %d\n", protectiveMBR.WriteMBRData(device));
|
||||
return numConverted;
|
||||
} // GPTData::XFormToMBR()
|
||||
|
||||
@@ -1774,7 +1770,8 @@ void GPTData::MakeHybrid(void) {
|
||||
**********************************************************************/
|
||||
|
||||
// Resizes GPT to specified number of entries. Creates a new table if
|
||||
// necessary, copies data if it already exists.
|
||||
// necessary, copies data if it already exists. Returns 1 if all goes
|
||||
// well, 0 if an error is encountered.
|
||||
int GPTData::SetGPTSize(uint32_t numEntries) {
|
||||
struct GPTPart* newParts;
|
||||
struct GPTPart* trash;
|
||||
@@ -1844,6 +1841,51 @@ void GPTData::BlankPartitions(void) {
|
||||
} // for
|
||||
} // GPTData::BlankPartitions()
|
||||
|
||||
// Delete a partition by number. Returns 1 if successful,
|
||||
// 0 if there was a problem. Returns 1 if partition was in
|
||||
// range, 0 if it was out of range.
|
||||
int GPTData::DeletePartition(uint32_t partNum) {
|
||||
uint64_t startSector, length;
|
||||
uint32_t low, high, numParts, retval = 1;;
|
||||
|
||||
numParts = GetPartRange(&low, &high);
|
||||
if ((numParts > 0) && (partNum >= low) && (partNum <= high)) {
|
||||
// In case there's a protective MBR, look for & delete matching
|
||||
// MBR partition....
|
||||
startSector = partitions[partNum].GetFirstLBA();
|
||||
length = partitions[partNum].GetLengthLBA();
|
||||
protectiveMBR.DeleteByLocation(startSector, length);
|
||||
|
||||
// Now delete the GPT partition
|
||||
partitions[partNum].BlankPartition();
|
||||
} else {
|
||||
fprintf(stderr, "Partition number %d out of range!\n", partNum + 1);
|
||||
retval = 0;
|
||||
} // if/else
|
||||
return retval;
|
||||
} // GPTData::DeletePartition(uint32_t partNum)
|
||||
|
||||
// Non-interactively create a partition. Note that this function is overloaded
|
||||
// with another of the same name but different parameters; that one prompts
|
||||
// the user for data. This one returns 1 if the operation was successful, 0
|
||||
// if a problem was discovered.
|
||||
int GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) {
|
||||
int retval = 1; // assume there'll be no problems
|
||||
|
||||
if (IsFreePartNum(partNum)) {
|
||||
Align(&startSector); // Align sector to correct multiple
|
||||
if (IsFree(startSector) && (startSector <= endSector)) {
|
||||
if (FindLastInFree(startSector) >= endSector) {
|
||||
partitions[partNum].SetFirstLBA(startSector);
|
||||
partitions[partNum].SetLastLBA(endSector);
|
||||
partitions[partNum].SetType(0x0700);
|
||||
partitions[partNum].SetUniqueGUID(1);
|
||||
} else retval = 0; // if free space until endSector
|
||||
} else retval = 0; // if startSector is free
|
||||
} else retval = 0; // if legal partition number
|
||||
return retval;
|
||||
} // GPTData::CreatePartition(partNum, startSector, endSector)
|
||||
|
||||
// Sort the GPT entries, eliminating gaps and making for a logical
|
||||
// ordering. Relies on QuickSortGPT() for the bulk of the work
|
||||
void GPTData::SortGPT(void) {
|
||||
@@ -1934,10 +1976,13 @@ void GPTData::MoveSecondHeaderToEnd() {
|
||||
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
|
||||
} // GPTData::FixSecondHeaderLocation()
|
||||
|
||||
void GPTData::SetName(uint32_t partNum, char* theName) {
|
||||
if ((partNum >= 0) && (partNum < mainHeader.numParts))
|
||||
if (partitions[partNum].GetFirstLBA() > 0)
|
||||
partitions[partNum].SetName((unsigned char*) theName);
|
||||
int GPTData::SetName(uint32_t partNum, char* theName) {
|
||||
int retval = 1;
|
||||
if (!IsFreePartNum(partNum))
|
||||
partitions[partNum].SetName((unsigned char*) theName);
|
||||
else retval = 0;
|
||||
|
||||
return retval;
|
||||
} // GPTData::SetName
|
||||
|
||||
// Set the disk GUID to the specified value. Note that the header CRCs must
|
||||
@@ -1962,6 +2007,17 @@ int GPTData::SetPartitionGUID(uint32_t pn, GUIDData theGUID) {
|
||||
return retval;
|
||||
} // GPTData::SetPartitionGUID()
|
||||
|
||||
// Change partition type code non-interactively. Returns 1 if
|
||||
// successful, 0 if not....
|
||||
int GPTData::ChangePartType(uint32_t partNum, uint16_t hexCode) {
|
||||
int retval = 1;
|
||||
|
||||
if (!IsFreePartNum(partNum)) {
|
||||
partitions[partNum].SetType(hexCode);
|
||||
} else retval = 0;
|
||||
return retval;
|
||||
} // GPTData::ChangePartType()
|
||||
|
||||
// Adjust sector number so that it falls on a sector boundary that's a
|
||||
// multiple of sectorAlignment. This is done to improve the performance
|
||||
// of Western Digital Advanced Format disks and disks with similar
|
||||
@@ -2015,8 +2071,10 @@ int GPTData::Align(uint64_t* sector) {
|
||||
// Otherwise, notify the user that it couldn't be done....
|
||||
if (sectorOK == 1) {
|
||||
printf("Information: Moved requested sector from %llu to %llu for\n"
|
||||
"alignment purposes. Use 'l' on the experts' menu to adjust alignment.\n",
|
||||
"alignment purposes.\n",
|
||||
(unsigned long long) original, (unsigned long long) *sector);
|
||||
if (!beQuiet)
|
||||
printf("Use 'l' on the experts' menu to adjust alignment\n");
|
||||
} else {
|
||||
printf("Information: Sector not aligned on %d-sector boundary and could not be moved.\n"
|
||||
"If you're using a Western Digital Advanced Format or similar disk with\n"
|
||||
@@ -2227,6 +2285,20 @@ int GPTData::IsFree(uint64_t sector) {
|
||||
return (isFree);
|
||||
} // GPTData::IsFree()
|
||||
|
||||
// Returns 1 if partNum is unused.
|
||||
int GPTData::IsFreePartNum(uint32_t partNum) {
|
||||
int retval = 1;
|
||||
|
||||
if ((partNum >= 0) && (partNum < mainHeader.numParts)) {
|
||||
if ((partitions[partNum].GetFirstLBA() != UINT64_C(0)) ||
|
||||
(partitions[partNum].GetLastLBA() != UINT64_C(0))) {
|
||||
retval = 0;
|
||||
} // if partition is in use
|
||||
} else retval = 0;
|
||||
|
||||
return retval;
|
||||
} // GPTData::IsFreePartNum()
|
||||
|
||||
/********************************
|
||||
* *
|
||||
* Endianness support functions *
|
||||
|
||||
23
gpt.h
23
gpt.h
@@ -32,6 +32,7 @@ enum GPTValidity {gpt_valid, gpt_corrupt, gpt_invalid};
|
||||
enum WhichToUse {use_gpt, use_mbr, use_bsd, use_new};
|
||||
|
||||
// Header (first 512 bytes) of GPT table
|
||||
#pragma pack(1)
|
||||
struct GPTHeader {
|
||||
uint64_t signature;
|
||||
uint32_t revision;
|
||||
@@ -54,7 +55,7 @@ struct GPTHeader {
|
||||
class GPTData {
|
||||
protected:
|
||||
struct GPTHeader mainHeader;
|
||||
struct GPTPart *partitions;
|
||||
GPTPart *partitions;
|
||||
struct GPTHeader secondHeader;
|
||||
MBRData protectiveMBR;
|
||||
char device[256]; // device filename
|
||||
@@ -70,6 +71,8 @@ protected:
|
||||
int bsdFound; // set to 1 if BSD disklabel detected in MBR
|
||||
int sectorAlignment; // Start & end partitions at multiples of sectorAlignment
|
||||
PartTypes typeHelper;
|
||||
int beQuiet;
|
||||
WhichToUse whichWasUsed;
|
||||
public:
|
||||
// Basic necessary functions....
|
||||
GPTData(void);
|
||||
@@ -94,7 +97,7 @@ public:
|
||||
int ForceLoadGPTData(int fd);
|
||||
int LoadMainTable(void);
|
||||
void LoadSecondTableAsMain(void);
|
||||
int SaveGPTData(void);
|
||||
int SaveGPTData(int quiet = 0);
|
||||
int SaveGPTBackup(char* filename);
|
||||
int LoadGPTBackup(char* filename);
|
||||
|
||||
@@ -127,16 +130,17 @@ public:
|
||||
// Adjust GPT structures WITHOUT user interaction...
|
||||
int SetGPTSize(uint32_t numEntries);
|
||||
void BlankPartitions(void);
|
||||
int DeletePartition(uint32_t partNum);
|
||||
int CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector);
|
||||
void SortGPT(void);
|
||||
int ClearGPTData(void);
|
||||
void MoveSecondHeaderToEnd();
|
||||
void SetName(uint32_t partNum, char* theName = NULL);
|
||||
int SetName(uint32_t partNum, char* theName = NULL);
|
||||
void SetDiskGUID(GUIDData newGUID);
|
||||
int SetPartitionGUID(uint32_t pn, GUIDData theGUID);
|
||||
int ChangePartType(uint32_t pn, uint16_t hexCode);
|
||||
void MakeProtectiveMBR(void) {protectiveMBR.MakeProtectiveMBR();}
|
||||
int Align(uint64_t* sector);
|
||||
void SetAlignment(int n) {sectorAlignment = n;}
|
||||
void JustLooking(int i = 1) {justLooking = i;}
|
||||
|
||||
// Return data about the GPT structures....
|
||||
int GetPartRange(uint32_t* low, uint32_t* high);
|
||||
@@ -146,7 +150,6 @@ public:
|
||||
uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
|
||||
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
|
||||
uint32_t CountParts(void);
|
||||
int GetAlignment(void) {return sectorAlignment;}
|
||||
|
||||
// Find information about free space
|
||||
uint64_t FindFirstAvailable(uint64_t start = 0);
|
||||
@@ -155,6 +158,14 @@ public:
|
||||
uint64_t FindLastInFree(uint64_t start);
|
||||
uint64_t FindFreeBlocks(int *numSegments, uint64_t *largestSegment);
|
||||
int IsFree(uint64_t sector);
|
||||
int IsFreePartNum(uint32_t partNum);
|
||||
|
||||
// Change how functions work, or return information on same
|
||||
void SetAlignment(int n) {sectorAlignment = n;}
|
||||
int GetAlignment(void) {return sectorAlignment;}
|
||||
void JustLooking(int i = 1) {justLooking = i;}
|
||||
void BeQuiet(int i = 1) {beQuiet = i;}
|
||||
WhichToUse WhichWasUsed(void) {return whichWasUsed;}
|
||||
|
||||
// Endianness functions
|
||||
void ReverseHeaderBytes(struct GPTHeader* header); // for endianness
|
||||
|
||||
@@ -206,7 +206,7 @@ void GPTPart::ChangeType(void) {
|
||||
else // user wants to enter the GUID directly, so do that
|
||||
newType = GetGUID();
|
||||
partitionType = newType;
|
||||
printf("Changed system type of partition to '%s'\n",
|
||||
printf("Changed type of partition to '%s'\n",
|
||||
typeHelper.GUIDToName(partitionType, typeName));
|
||||
} // GPTPart::ChangeType()
|
||||
|
||||
@@ -278,4 +278,3 @@ void QuickSortGPT(GPTPart* partitions, int start, int finish) {
|
||||
if (start < right) QuickSortGPT(partitions, start, right);
|
||||
if (finish > left) QuickSortGPT(partitions, left, finish);
|
||||
} // QuickSortGPT()
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@ using namespace std;
|
||||
|
||||
class GPTPart {
|
||||
protected:
|
||||
// Caution: The non-static data in GUIDPart is precisely the right size
|
||||
// Caution: The non-static data in GPTPart is precisely the right size
|
||||
// to enable easy loading of the data directly from disk. If any
|
||||
// non-static variables are added to the below, the data size will
|
||||
// change and the program will stop working. This can be corrected by
|
||||
// adjusting the data-load operation in GPTData::LoadMainTable() and
|
||||
// GPTData::LoadSecondTableAsMain() and then removing the GUIDPart
|
||||
// size check in SizesOK().
|
||||
// GPTData::LoadSecondTableAsMain() and then removing the GPTPart
|
||||
// size check in SizesOK() (in gpt.cc file).
|
||||
struct GUIDData partitionType;
|
||||
struct GUIDData uniqueGUID;
|
||||
uint64_t firstLBA;
|
||||
|
||||
5
mbr.cc
5
mbr.cc
@@ -305,6 +305,11 @@ void MBRData::WriteMBRData(int fd) {
|
||||
}// if
|
||||
} // MBRData::WriteMBRData(int fd)
|
||||
|
||||
int MBRData::WriteMBRData(char* deviceFilename) {
|
||||
strcpy(device, deviceFilename);
|
||||
return WriteMBRData();
|
||||
} // MBRData::WriteMBRData(char* deviceFilename)
|
||||
|
||||
/********************************************
|
||||
* *
|
||||
* Functions that display data for the user *
|
||||
|
||||
7
mbr.h
7
mbr.h
@@ -30,6 +30,7 @@ using namespace std;
|
||||
// Data for a single MBR partition record
|
||||
// Note that firstSector and lastSector are in CHS addressing, which
|
||||
// splits the bits up in a weird way.
|
||||
#pragma pack(1)
|
||||
struct MBRRecord {
|
||||
uint8_t status;
|
||||
uint8_t firstSector[3];
|
||||
@@ -43,6 +44,7 @@ struct MBRRecord {
|
||||
// go, for the benefit of FreeBSD which seems to flake out when loading
|
||||
// from block devices in multiples other than the block size.
|
||||
// Also used when loading logical partitions.
|
||||
#pragma pack(1)
|
||||
struct TempMBR {
|
||||
uint8_t code[440];
|
||||
uint32_t diskSignature;
|
||||
@@ -81,12 +83,13 @@ public:
|
||||
// File I/O functions...
|
||||
int ReadMBRData(char* deviceFilename);
|
||||
void ReadMBRData(int fd, int checkBlockSize = 1);
|
||||
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
||||
// or -1 if there was a problem....
|
||||
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
||||
int partNum);
|
||||
int WriteMBRData(void);
|
||||
void WriteMBRData(int fd);
|
||||
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
||||
// or -1 if there was a problem....
|
||||
int WriteMBRData(char* deviceFilename);
|
||||
|
||||
// Display data for user...
|
||||
void DisplayMBRData(void);
|
||||
|
||||
64
support.cc
64
support.cc
@@ -27,6 +27,10 @@
|
||||
#define BLKPBSZGET _IO(0x12,123)
|
||||
#endif
|
||||
|
||||
// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
|
||||
// cutoff
|
||||
#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Get a numeric value from the user, between low and high (inclusive).
|
||||
@@ -84,8 +88,7 @@ char GetYN(void) {
|
||||
//value as the default if the user just hits Enter
|
||||
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[]) {
|
||||
unsigned long long response;
|
||||
int num;
|
||||
int plusFlag = 0;
|
||||
int num, plusFlag = 0;
|
||||
uint64_t mult = 1;
|
||||
char suffix;
|
||||
char line[255];
|
||||
@@ -147,7 +150,14 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[])
|
||||
// Adjust response based on multiplier and plus flag, if present
|
||||
response *= (unsigned long long) mult;
|
||||
if (plusFlag == 1) {
|
||||
response = response + (unsigned long long) low - UINT64_C(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
|
||||
// range) or the defaut value (if default != high, which should be
|
||||
// the case for the first sector of a partition).
|
||||
if (def == high)
|
||||
response = response + (unsigned long long) low - UINT64_C(1);
|
||||
else
|
||||
response = response + (unsigned long long) def - UINT64_C(1);
|
||||
} // if
|
||||
if (plusFlag == -1) {
|
||||
response = (unsigned long long) high - response;
|
||||
@@ -231,29 +241,65 @@ int GetBlockSize(int fd) {
|
||||
return (result);
|
||||
} // GetBlockSize()
|
||||
|
||||
// My original FindAlignment() function (after this one) isn't working, since
|
||||
// the BLKPBSZGET ioctl() isn't doing what I expected (it returns 512 even on
|
||||
// a WD Advanced Format drive). Therefore, I'm using a simpler function that
|
||||
// returns 1-sector alignment for unusual sector sizes and drives smaller than
|
||||
// a size defined by SMALLEST_ADVANCED_FORMAT, and 8-sector alignment for
|
||||
// larger drives with 512-byte sectors.
|
||||
int FindAlignment(int fd) {
|
||||
int err, result;
|
||||
|
||||
if ((GetBlockSize(fd) == 512) && (disksize(fd, &err) >= SMALLEST_ADVANCED_FORMAT)) {
|
||||
result = 8; // play it safe; align for 4096-byte sectors
|
||||
} else {
|
||||
result = 1; // unusual sector size; assume it's the real physical size
|
||||
} // if/else
|
||||
return result;
|
||||
} // FindAlignment
|
||||
|
||||
// Return the partition alignment value in sectors. Right now this works
|
||||
// only for Linux 2.6.32 and later, since I can't find equivalent ioctl()s
|
||||
// for OS X or FreeBSD, and the Linux ioctl is new
|
||||
int FindAlignment(int fd) {
|
||||
int err = -2, result = 8, physicalSectorSize = 4096;
|
||||
/* int FindAlignment(int fd) {
|
||||
int err = -2, errnum = 0, result = 8, physicalSectorSize = 4096;
|
||||
uint64_t diskSize;
|
||||
|
||||
printf("Entering FindAlignment()\n");
|
||||
#if defined (__linux__) && defined (BLKPBSZGET)
|
||||
err = ioctl(fd, BLKPBSZGET, &physicalSectorSize);
|
||||
printf("In FindAlignment(), physicalSectorSize = %d, err = %d\n", physicalSectorSize, err);
|
||||
// printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize);
|
||||
#else
|
||||
err = -1;
|
||||
#endif
|
||||
|
||||
if (err < 0) { // ioctl didn't work; have to guess....
|
||||
if (GetBlockSize(fd) == 512)
|
||||
if (GetBlockSize(fd) == 512) {
|
||||
result = 8; // play it safe; align for 4096-byte sectors
|
||||
else
|
||||
result = 1; // unusual sector size; assume it's the real physical size
|
||||
} else {
|
||||
result = 1; // unusual sector size; assume it's the real physical size
|
||||
} // if/else
|
||||
} else { // ioctl worked; compute alignment
|
||||
result = physicalSectorSize / GetBlockSize(fd);
|
||||
// Disks with larger physical than logical sectors must theoretically
|
||||
// have a total disk size that's a multiple of the physical sector
|
||||
// size; however, some such disks have compatibility jumper settings
|
||||
// meant for one-partition MBR setups, and these reduce the total
|
||||
// number of sectors by 1. If such a setting is used, it'll result
|
||||
// in improper alignment, so look for this condition and warn the
|
||||
// user if it's found....
|
||||
diskSize = disksize(fd, &errnum);
|
||||
if ((diskSize % (uint64_t) result) != 0) {
|
||||
fprintf(stderr, "\aWarning! Disk size (%llu) is not a multiple of alignment\n"
|
||||
"size (%d), but it should be! Check disk manual and jumper settings!\n",
|
||||
(unsigned long long) diskSize, result);
|
||||
} // if
|
||||
} // if/else
|
||||
if (result <= 0) // can happen if physical sector size < logical sector size
|
||||
result = 1;
|
||||
return result;
|
||||
} // FindAlignment(int)
|
||||
} // FindAlignment(int) */
|
||||
|
||||
// The same as FindAlignment(int), but opens and closes a device by filename
|
||||
int FindAlignment(char deviceFilename[]) {
|
||||
|
||||
Reference in New Issue
Block a user