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