GPT fdisk 0.5.0
Added several features, including a restructuring of the menu system, GPT-to-MBR conversion, and the ability to re-read the MBR to generate a fresh GPT from the current on-disk MBR.
This commit is contained in:
42
CHANGELOG
42
CHANGELOG
@@ -1,3 +1,45 @@
|
|||||||
|
0.5.0:
|
||||||
|
------
|
||||||
|
|
||||||
|
- Added GPT-to-MBR conversion function. It's very limited, but potentially
|
||||||
|
useful in some cases.
|
||||||
|
|
||||||
|
- Fixed bug that caused incorrect file sizes to be reported on 32-bit
|
||||||
|
Linux, thus causing problems when editing partition tables in disk images
|
||||||
|
or when loading GPT backup files.
|
||||||
|
|
||||||
|
- Fixed bug that caused bogus CRC error reports when loading backup GPT
|
||||||
|
data.
|
||||||
|
|
||||||
|
- Reorganized menus. There are now three: the main menu, the experts' menu,
|
||||||
|
and the recovery & transformation menu. The last of these has most of the
|
||||||
|
items that had been on the earlier versions' experts' menu.
|
||||||
|
|
||||||
|
- Added ability to re-load the MBR and generate a fresh GPT from it. This
|
||||||
|
is normally identical to quitting and re-running the program, but it
|
||||||
|
could be handy if, say, the GPT partitions on a hybrid configuration are
|
||||||
|
badly messed up; this will enable using the hybridized partitions as the
|
||||||
|
starting point for a new GPT setup.
|
||||||
|
|
||||||
|
- The program now generates CHS values for hybrid and GPT-to-MBR conversion
|
||||||
|
MBRs. For the moment, the assumption is the maximum number of heads and
|
||||||
|
sectors per track (255 and 63, respectively), although the bulk of the
|
||||||
|
code supports other values -- it'd just be awkward to enter the data in
|
||||||
|
the user interface.
|
||||||
|
|
||||||
|
- Fixed minor display bug that caused number of sectors on the disk to be
|
||||||
|
shown as 0 on large disks when running 32-bit binaries.
|
||||||
|
|
||||||
|
- Reverted 0.4.2's zap (destroy GPT) changes, since I don't want to wipe
|
||||||
|
out a valid MBR if the user created that MBR over an older GPT without
|
||||||
|
first properly wiping out the GPT, and the user now wants to wipe out
|
||||||
|
the GPT.
|
||||||
|
|
||||||
|
- Reformatted and edited the man page. Aside from edits related to the
|
||||||
|
preceding program changes, I've altered the markup slightly and trimmed
|
||||||
|
much of the more tutorial information from the man page to better
|
||||||
|
conform to typical terse man page style.
|
||||||
|
|
||||||
0.4.2:
|
0.4.2:
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -28,6 +28,6 @@ clean: #no pre-reqs
|
|||||||
depend: $(SRCS)
|
depend: $(SRCS)
|
||||||
$(DEPEND) $(SRCS)
|
$(DEPEND) $(SRCS)
|
||||||
|
|
||||||
$(OBJS):
|
$(OBJS):
|
||||||
|
|
||||||
# DO NOT DELETE
|
# DO NOT DELETE
|
||||||
|
|||||||
364
gdisk.cc
364
gdisk.cc
@@ -17,25 +17,27 @@
|
|||||||
|
|
||||||
// Function prototypes....
|
// Function prototypes....
|
||||||
// int ReadPartitions(char* filename, struct GPTData* theGPT);
|
// int ReadPartitions(char* filename, struct GPTData* theGPT);
|
||||||
int DoCommand(char* filename, struct GPTData* theGPT);
|
void MainMenu(char* filename, struct GPTData* theGPT);
|
||||||
void ShowCommands(void);
|
void ShowCommands(void);
|
||||||
|
void ExpertsMenu(char* filename, struct GPTData* theGPT);
|
||||||
void ShowExpertCommands(void);
|
void ShowExpertCommands(void);
|
||||||
int ExpertsMenu(char* filename, struct GPTData* theGPT);
|
void RecoveryMenu(char* filename, struct GPTData* theGPT);
|
||||||
|
void ShowRecoveryCommands(void);
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
GPTData theGPT;
|
GPTData theGPT;
|
||||||
int doMore = 1;
|
int doMore = 1;
|
||||||
char* device = NULL;
|
char* device = NULL;
|
||||||
|
|
||||||
printf("GPT fdisk (gdisk) version 0.4.2\n\n");
|
printf("GPT fdisk (gdisk) version 0.5.0\n\n");
|
||||||
|
|
||||||
if (argc == 2) { // basic usage
|
if (argc == 2) { // basic usage
|
||||||
if (SizesOK()) {
|
if (SizesOK()) {
|
||||||
doMore = theGPT.LoadPartitions(argv[1]);
|
doMore = theGPT.LoadPartitions(argv[1]);
|
||||||
while (doMore) {
|
if (doMore) {
|
||||||
doMore = DoCommand(argv[1], &theGPT);
|
MainMenu(argv[1], &theGPT);
|
||||||
} // while
|
} // if (doMore)
|
||||||
} // if
|
} // if (SizesOK())
|
||||||
} else if (argc == 3) { // usage with "-l" option
|
} else if (argc == 3) { // usage with "-l" option
|
||||||
if (SizesOK()) {
|
if (SizesOK()) {
|
||||||
if (strcmp(argv[1], "-l") == 0) {
|
if (strcmp(argv[1], "-l") == 0) {
|
||||||
@@ -55,112 +57,242 @@ int main(int argc, char* argv[]) {
|
|||||||
} // if/else
|
} // if/else
|
||||||
} // main
|
} // main
|
||||||
|
|
||||||
// Accept a command and execute it. Returns 0 if the command includes
|
// Accept a command and execute it. Returns only when the user
|
||||||
// an exit condition (such as a q or w command), 1 if more commands
|
// wants to exit (such as after a 'w' or 'q' command).
|
||||||
// should be processed.
|
void MainMenu(char* filename, struct GPTData* theGPT) {
|
||||||
int DoCommand(char* filename, struct GPTData* theGPT) {
|
char command, line[255], buFile[255];
|
||||||
char command, line[255];
|
int goOn = 1;
|
||||||
int retval = 1;
|
|
||||||
PartTypes typeHelper;
|
PartTypes typeHelper;
|
||||||
uint32_t temp1, temp2;
|
uint32_t temp1, temp2;
|
||||||
|
|
||||||
printf("\nCommand (m for help): ");
|
do {
|
||||||
fgets(line, 255, stdin);
|
printf("\nCommand (? for help): ");
|
||||||
sscanf(line, "%c", &command);
|
fgets(line, 255, stdin);
|
||||||
switch (command) {
|
sscanf(line, "%c", &command);
|
||||||
case 'b': case 'B':
|
switch (command) {
|
||||||
theGPT->XFormDisklabel();
|
case 'b': case 'B':
|
||||||
break;
|
printf("Enter backup filename to save: ");
|
||||||
case 'c': case 'C':
|
fgets(line, 255, stdin);
|
||||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
sscanf(line, "%s", &buFile);
|
||||||
theGPT->SetName(theGPT->GetPartNum());
|
theGPT->SaveGPTBackup(buFile);
|
||||||
else
|
break;
|
||||||
printf("No partitions\n");
|
case 'c': case 'C':
|
||||||
break;
|
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
||||||
case 'd': case 'D':
|
theGPT->SetName(theGPT->GetPartNum());
|
||||||
theGPT->DeletePartition();
|
else
|
||||||
break;
|
printf("No partitions\n");
|
||||||
case 'i': case 'I':
|
break;
|
||||||
theGPT->ShowDetails();
|
case 'd': case 'D':
|
||||||
break;
|
theGPT->DeletePartition();
|
||||||
case 'l': case 'L':
|
break;
|
||||||
typeHelper.ShowTypes();
|
case 'i': case 'I':
|
||||||
break;
|
theGPT->ShowDetails();
|
||||||
case 'n': case 'N':
|
break;
|
||||||
theGPT->CreatePartition();
|
case 'l': case 'L':
|
||||||
break;
|
typeHelper.ShowTypes();
|
||||||
case 'o': case 'O':
|
break;
|
||||||
printf("This option deletes all partitions and creates a new "
|
case 'n': case 'N':
|
||||||
"protective MBR.\nProceed? ");
|
theGPT->CreatePartition();
|
||||||
if (GetYN() == 'Y') {
|
break;
|
||||||
theGPT->ClearGPTData();
|
case 'o': case 'O':
|
||||||
theGPT->MakeProtectiveMBR();
|
printf("This option deletes all partitions and creates a new "
|
||||||
} // if
|
"protective MBR.\nProceed? ");
|
||||||
break;
|
if (GetYN() == 'Y') {
|
||||||
case 'p': case 'P':
|
theGPT->ClearGPTData();
|
||||||
theGPT->DisplayGPTData();
|
theGPT->MakeProtectiveMBR();
|
||||||
break;
|
} // if
|
||||||
case 'q': case 'Q':
|
break;
|
||||||
retval = 0;
|
case 'p': case 'P':
|
||||||
break;
|
theGPT->DisplayGPTData();
|
||||||
case 's': case 'S':
|
break;
|
||||||
theGPT->SortGPT();
|
case 'q': case 'Q':
|
||||||
printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
|
goOn = 0;
|
||||||
break;
|
break;
|
||||||
case 't': case 'T':
|
case 'r': case 'R':
|
||||||
theGPT->ChangePartType();
|
RecoveryMenu(filename, theGPT);
|
||||||
break;
|
goOn = 0;
|
||||||
case 'v': case 'V':
|
break;
|
||||||
if (theGPT->Verify() > 0) { // problems found
|
case 's': case 'S':
|
||||||
printf("You may be able to correct the problems by using options on the experts\n"
|
theGPT->SortGPT();
|
||||||
"menu (press 'x' at the command prompt). Good luck!\n");
|
printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
|
||||||
} // if
|
break;
|
||||||
break;
|
case 't': case 'T':
|
||||||
case 'w': case 'W':
|
theGPT->ChangePartType();
|
||||||
if (theGPT->SaveGPTData() == 1)
|
break;
|
||||||
retval = 0;
|
case 'v': case 'V':
|
||||||
break;
|
if (theGPT->Verify() > 0) { // problems found
|
||||||
case 'x': case 'X':
|
printf("You may be able to correct the problems by using options on the experts\n"
|
||||||
retval = ExpertsMenu(filename, theGPT);
|
"menu (press 'x' at the command prompt). Good luck!\n");
|
||||||
break;
|
} // if
|
||||||
default:
|
break;
|
||||||
ShowCommands();
|
case 'w': case 'W':
|
||||||
break;
|
if (theGPT->SaveGPTData() == 1)
|
||||||
} // switch
|
goOn = 0;
|
||||||
return (retval);
|
break;
|
||||||
} // DoCommand()
|
case 'x': case 'X':
|
||||||
|
ExpertsMenu(filename, theGPT);
|
||||||
|
goOn = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ShowCommands();
|
||||||
|
break;
|
||||||
|
} // switch
|
||||||
|
} while (goOn);
|
||||||
|
} // MainMenu()
|
||||||
|
|
||||||
void ShowCommands(void) {
|
void ShowCommands(void) {
|
||||||
printf("b\tconvert BSD disklabel partitions\n");
|
printf("b\tback up GPT data to a file\n");
|
||||||
printf("c\tchange a partition's name\n");
|
printf("c\tchange a partition's name\n");
|
||||||
printf("d\tdelete a partition\n");
|
printf("d\tdelete a partition\n");
|
||||||
printf("i\tshow detailed information on a partition\n");
|
printf("i\tshow detailed information on a partition\n");
|
||||||
printf("l\tlist available partition types\n");
|
printf("l\tlist known partition types\n");
|
||||||
printf("m\tprint this menu\n");
|
|
||||||
printf("n\tadd a new partition\n");
|
printf("n\tadd a new partition\n");
|
||||||
printf("o\tcreate a new empty GUID partition table (GPT)\n");
|
printf("o\tcreate a new empty GUID partition table (GPT)\n");
|
||||||
printf("p\tprint the partition table\n");
|
printf("p\tprint the partition table\n");
|
||||||
printf("q\tquit without saving changes\n");
|
printf("q\tquit without saving changes\n");
|
||||||
|
printf("r\trecovery and transformation options (experts only)\n");
|
||||||
printf("s\tsort partitions\n");
|
printf("s\tsort partitions\n");
|
||||||
printf("t\tchange a partition's type code\n");
|
printf("t\tchange a partition's type code\n");
|
||||||
printf("v\tverify disk\n");
|
printf("v\tverify disk\n");
|
||||||
printf("w\twrite table to disk and exit\n");
|
printf("w\twrite table to disk and exit\n");
|
||||||
printf("x\textra functionality (experts only)\n");
|
printf("x\textra functionality (experts only)\n");
|
||||||
|
printf("?\tprint this menu\n");
|
||||||
} // ShowCommands()
|
} // ShowCommands()
|
||||||
|
|
||||||
// Accept a command and execute it. Returns 0 if the command includes
|
// Accept a recovery & transformation menu command. Returns only when the user
|
||||||
// an exit condition (such as a q or w command), 1 if more commands
|
// issues an exit command, such as 'w' or 'q'.
|
||||||
// should be processed.
|
void RecoveryMenu(char* filename, struct GPTData* theGPT) {
|
||||||
int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|
||||||
char command, line[255], buFile[255];
|
char command, line[255], buFile[255];
|
||||||
int retval = 1;
|
PartTypes typeHelper;
|
||||||
|
uint32_t temp1;
|
||||||
|
int goOn = 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
printf("\nrecovery/transformation command (? for help): ");
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
sscanf(line, "%c", &command);
|
||||||
|
switch (command) {
|
||||||
|
case 'b': case 'B':
|
||||||
|
theGPT->RebuildMainHeader();
|
||||||
|
break;
|
||||||
|
case 'c': case 'C':
|
||||||
|
printf("Warning! This will probably do weird things if you've converted an MBR to\n"
|
||||||
|
"GPT form and haven't yet saved the GPT! Proceed? ");
|
||||||
|
if (GetYN() == 'Y')
|
||||||
|
theGPT->LoadSecondTableAsMain();
|
||||||
|
break;
|
||||||
|
case 'd': case 'D':
|
||||||
|
theGPT->RebuildSecondHeader();
|
||||||
|
break;
|
||||||
|
case 'e': case 'E':
|
||||||
|
printf("Warning! This will probably do weird things if you've converted an MBR to\n"
|
||||||
|
"GPT form and haven't yet saved the GPT! Proceed? ");
|
||||||
|
if (GetYN() == 'Y')
|
||||||
|
theGPT->LoadMainTable();
|
||||||
|
break;
|
||||||
|
case 'f': case 'F':
|
||||||
|
printf("Warning! This will destroy the currently defined partitions! Proceed? ");
|
||||||
|
if (GetYN() == 'Y') {
|
||||||
|
if (theGPT->LoadMBR(filename) == 1) { // successful load
|
||||||
|
theGPT->XFormPartitions();
|
||||||
|
} else {
|
||||||
|
printf("Problem loading MBR! GPT is untouched; regenerating protective MBR!\n");
|
||||||
|
theGPT->MakeProtectiveMBR();
|
||||||
|
} // if/else
|
||||||
|
} // if
|
||||||
|
break;
|
||||||
|
case 'g': case 'G':
|
||||||
|
temp1 = theGPT->XFormToMBR();
|
||||||
|
if (temp1 > 0) {
|
||||||
|
printf("Converted %d partitions. Finalize and exit? ", temp1);
|
||||||
|
if (GetYN() == 'Y') {
|
||||||
|
if (theGPT->DestroyGPT(0) > 0)
|
||||||
|
goOn = 0;
|
||||||
|
} else {
|
||||||
|
theGPT->MakeProtectiveMBR();
|
||||||
|
printf("Note: New protective MBR created.\n");
|
||||||
|
} // if/else
|
||||||
|
} // if
|
||||||
|
break;
|
||||||
|
case 'h': case 'H':
|
||||||
|
theGPT->MakeHybrid();
|
||||||
|
break;
|
||||||
|
case 'i': case 'I':
|
||||||
|
theGPT->ShowDetails();
|
||||||
|
break;
|
||||||
|
case 'l': case 'L':
|
||||||
|
printf("Enter backup filename to load: ");
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
sscanf(line, "%s", &buFile);
|
||||||
|
theGPT->LoadGPTBackup(buFile);
|
||||||
|
break;
|
||||||
|
case 'm': case 'M':
|
||||||
|
MainMenu(filename, theGPT);
|
||||||
|
goOn = 0;
|
||||||
|
break;
|
||||||
|
case 'o': case 'O':
|
||||||
|
theGPT->DisplayMBRData();
|
||||||
|
break;
|
||||||
|
case 'p': case 'P':
|
||||||
|
theGPT->DisplayGPTData();
|
||||||
|
break;
|
||||||
|
case 'q': case 'Q':
|
||||||
|
goOn = 0;
|
||||||
|
break;
|
||||||
|
case 't': case 'T':
|
||||||
|
theGPT->XFormDisklabel();
|
||||||
|
break;
|
||||||
|
case 'v': case 'V':
|
||||||
|
theGPT->Verify();
|
||||||
|
break;
|
||||||
|
case 'w': case 'W':
|
||||||
|
if (theGPT->SaveGPTData() == 1) {
|
||||||
|
goOn = 0;
|
||||||
|
} // if
|
||||||
|
break;
|
||||||
|
case 'x': case 'X':
|
||||||
|
ExpertsMenu(filename, theGPT);
|
||||||
|
goOn = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ShowRecoveryCommands();
|
||||||
|
break;
|
||||||
|
} // switch
|
||||||
|
} while (goOn);
|
||||||
|
} // RecoveryMenu()
|
||||||
|
|
||||||
|
void ShowRecoveryCommands(void) {
|
||||||
|
printf("b\tuse backup GPT header (rebuilding main)\n");
|
||||||
|
printf("c\tload backup partition table from disk (rebuilding main)\n");
|
||||||
|
printf("d\tuse main GPT header (rebuilding backup)\n");
|
||||||
|
printf("e\tload main partition table from disk (rebuilding backup)\n");
|
||||||
|
printf("f\tload MBR and build fresh GPT from it\n");
|
||||||
|
printf("g\tconvert GPT into MBR and exit\n");
|
||||||
|
printf("h\tmake hybrid MBR\n");
|
||||||
|
printf("i\tshow detailed information on a partition\n");
|
||||||
|
printf("l\tload partition data from a backup file\n");
|
||||||
|
printf("m\treturn to main menu\n");
|
||||||
|
printf("o\tprint protective MBR data\n");
|
||||||
|
printf("p\tprint the partition table\n");
|
||||||
|
printf("q\tquit without saving changes\n");
|
||||||
|
printf("t\ttransform BSD disklabel partition\n");
|
||||||
|
printf("v\tverify disk\n");
|
||||||
|
printf("w\twrite table to disk and exit\n");
|
||||||
|
printf("x\textra functionality (experts only)\n");
|
||||||
|
printf("?\tprint this menu\n");
|
||||||
|
} // ShowRecoveryCommands()
|
||||||
|
|
||||||
|
// Accept an experts' menu command. Returns only after the user
|
||||||
|
// selects an exit command, such as 'w' or 'q'.
|
||||||
|
void ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||||
|
char command, line[255];
|
||||||
PartTypes typeHelper;
|
PartTypes typeHelper;
|
||||||
uint32_t pn;
|
uint32_t pn;
|
||||||
uint32_t temp1, temp2;
|
uint32_t temp1, temp2;
|
||||||
int goOn = 1;
|
int goOn = 1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
printf("\nExpert command (m for help): ");
|
printf("\nExpert command (? for help): ");
|
||||||
fgets(line, 255, stdin);
|
fgets(line, 255, stdin);
|
||||||
sscanf(line, "%c", &command);
|
sscanf(line, "%c", &command);
|
||||||
switch (command) {
|
switch (command) {
|
||||||
@@ -170,25 +302,7 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
else
|
else
|
||||||
printf("No partitions\n");
|
printf("No partitions\n");
|
||||||
break;
|
break;
|
||||||
case 'b': case 'B':
|
|
||||||
theGPT->RebuildMainHeader();
|
|
||||||
break;
|
|
||||||
case 'c': case 'C':
|
case 'c': case 'C':
|
||||||
printf("Warning! This will probably do weird things if you've converted an MBR to\n"
|
|
||||||
"GPT form and haven't yet saved the GPT! Proceed? ");
|
|
||||||
if (GetYN() == 'Y')
|
|
||||||
theGPT->LoadSecondTableAsMain();
|
|
||||||
break;
|
|
||||||
case 'd': case 'D':
|
|
||||||
theGPT->RebuildSecondHeader();
|
|
||||||
break;
|
|
||||||
case 'e': case 'E':
|
|
||||||
printf("Warning! This will probably do weird things if you've converted an MBR to\n"
|
|
||||||
"GPT form and haven't yet saved the GPT! Proceed? ");
|
|
||||||
if (GetYN() == 'Y')
|
|
||||||
theGPT->LoadMainTable();
|
|
||||||
break;
|
|
||||||
case 'f': case 'F':
|
|
||||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
|
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
|
||||||
pn = theGPT->GetPartNum();
|
pn = theGPT->GetPartNum();
|
||||||
printf("Enter the partition's new unique GUID:\n");
|
printf("Enter the partition's new unique GUID:\n");
|
||||||
@@ -199,23 +313,12 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
printf("Enter the disk's unique GUID:\n");
|
printf("Enter the disk's unique GUID:\n");
|
||||||
theGPT->SetDiskGUID(GetGUID());
|
theGPT->SetDiskGUID(GetGUID());
|
||||||
break;
|
break;
|
||||||
case 'h': case 'H':
|
|
||||||
theGPT->MakeHybrid();
|
|
||||||
break;
|
|
||||||
case 'i': case 'I':
|
case 'i': case 'I':
|
||||||
theGPT->ShowDetails();
|
theGPT->ShowDetails();
|
||||||
break;
|
break;
|
||||||
case 'k': case 'K':
|
case 'm': case 'M':
|
||||||
printf("Enter backup filename to save: ");
|
MainMenu(filename, theGPT);
|
||||||
fgets(line, 255, stdin);
|
goOn = 0;
|
||||||
sscanf(line, "%s", &buFile);
|
|
||||||
theGPT->SaveGPTBackup(buFile);
|
|
||||||
break;
|
|
||||||
case 'l': case 'L':
|
|
||||||
printf("Enter backup filename to load: ");
|
|
||||||
fgets(line, 255, stdin);
|
|
||||||
sscanf(line, "%s", &buFile);
|
|
||||||
theGPT->LoadGPTBackup(buFile);
|
|
||||||
break;
|
break;
|
||||||
case 'n': case 'N':
|
case 'n': case 'N':
|
||||||
theGPT->MakeProtectiveMBR();
|
theGPT->MakeProtectiveMBR();
|
||||||
@@ -227,10 +330,10 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
theGPT->DisplayGPTData();
|
theGPT->DisplayGPTData();
|
||||||
break;
|
break;
|
||||||
case 'q': case 'Q':
|
case 'q': case 'Q':
|
||||||
retval = 0;
|
|
||||||
goOn = 0;
|
goOn = 0;
|
||||||
break;
|
break;
|
||||||
case 'r': case 'R':
|
case 'r': case 'R':
|
||||||
|
RecoveryMenu(filename, theGPT);
|
||||||
goOn = 0;
|
goOn = 0;
|
||||||
break;
|
break;
|
||||||
case 's': case 'S':
|
case 's': case 'S':
|
||||||
@@ -241,14 +344,12 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
break;
|
break;
|
||||||
case 'w': case 'W':
|
case 'w': case 'W':
|
||||||
if (theGPT->SaveGPTData() == 1) {
|
if (theGPT->SaveGPTData() == 1) {
|
||||||
retval = 0;
|
|
||||||
goOn = 0;
|
goOn = 0;
|
||||||
} // if
|
} // if
|
||||||
break;
|
break;
|
||||||
case 'z': case 'Z':
|
case 'z': case 'Z':
|
||||||
if (theGPT->DestroyGPT() == 1) {
|
if (theGPT->DestroyGPT() == 1) {
|
||||||
retval = 0;
|
goOn = 0;
|
||||||
goOn = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -256,29 +357,22 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
} while (goOn);
|
} while (goOn);
|
||||||
return (retval);
|
|
||||||
} // ExpertsMenu()
|
} // ExpertsMenu()
|
||||||
|
|
||||||
void ShowExpertCommands(void) {
|
void ShowExpertCommands(void) {
|
||||||
printf("a\tset attributes\n");
|
printf("a\tset attributes\n");
|
||||||
printf("b\tuse backup GPT header (rebuilding main)\n");
|
printf("c\tchange partition GUID\n");
|
||||||
printf("c\tload backup partition table from disk (rebuilding main)\n");
|
|
||||||
printf("d\tuse main GPT header (rebuilding backup)\n");
|
|
||||||
printf("e\tload main partition table from disk (rebuilding backup)\n");
|
|
||||||
printf("f\tchange partition GUID\n");
|
|
||||||
printf("g\tchange disk GUID\n");
|
printf("g\tchange disk GUID\n");
|
||||||
printf("h\tmake hybrid MBR\n");
|
|
||||||
printf("i\tshow detailed information on a partition\n");
|
printf("i\tshow detailed information on a partition\n");
|
||||||
printf("k\tsave partition data to a backup file\n");
|
printf("m\treturn to main menu\n");
|
||||||
printf("l\tload partition data from a backup file\n");
|
|
||||||
printf("m\tprint this 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");
|
||||||
printf("p\tprint the partition table\n");
|
printf("p\tprint the partition table\n");
|
||||||
printf("q\tquit without saving changes\n");
|
printf("q\tquit without saving changes\n");
|
||||||
printf("r\treturn to main menu\n");
|
printf("r\trecovery and transformation options (experts only)\n");
|
||||||
printf("s\tresize partition table\n");
|
printf("s\tresize partition table\n");
|
||||||
printf("v\tverify disk\n");
|
printf("v\tverify disk\n");
|
||||||
printf("w\twrite table to disk and exit\n");
|
printf("w\twrite table to disk and exit\n");
|
||||||
printf("z\tDestroy GPT data structures and exit\n");
|
printf("z\tzap (destroy) GPT data structures and exit\n");
|
||||||
|
printf("?\tprint this menu\n");
|
||||||
} // ShowExpertCommands()
|
} // ShowExpertCommands()
|
||||||
|
|||||||
251
gpt.cc
251
gpt.cc
@@ -112,7 +112,24 @@ int GPTData::Verify(void) {
|
|||||||
"table when you save your partitions.\n");
|
"table when you save your partitions.\n");
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// Now check that critical main and backup GPT entries match
|
// Now check that the main and backup headers both point to themselves....
|
||||||
|
if (mainHeader.currentLBA != 1) {
|
||||||
|
problems++;
|
||||||
|
printf("\nProblem: The main header's self-pointer doesn't point to itself. This problem\n"
|
||||||
|
"is being automatically corrected, but it may be a symptom of more serious\n"
|
||||||
|
"problems. Think carefully before saving changes with 'w' or using this disk.\n");
|
||||||
|
mainHeader.currentLBA = 1;
|
||||||
|
} // if
|
||||||
|
if (secondHeader.currentLBA != (diskSize - UINT64_C(1))) {
|
||||||
|
problems++;
|
||||||
|
printf("\nProblem: The secondary header's self-pointer doesn't point to itself. This\n"
|
||||||
|
"problem is being automatically corrected, but it may be a symptom of more\n"
|
||||||
|
"serious problems. Think carefully before saving changes with 'w' or using this\n"
|
||||||
|
"disk.\n");
|
||||||
|
secondHeader.currentLBA = diskSize - UINT64_C(1);
|
||||||
|
} // if
|
||||||
|
|
||||||
|
// Now check that critical main and backup GPT entries match each other
|
||||||
if (mainHeader.currentLBA != secondHeader.backupLBA) {
|
if (mainHeader.currentLBA != secondHeader.backupLBA) {
|
||||||
problems++;
|
problems++;
|
||||||
printf("\nProblem: main GPT header's current LBA pointer (%llu) doesn't\n"
|
printf("\nProblem: main GPT header's current LBA pointer (%llu) doesn't\n"
|
||||||
@@ -295,34 +312,38 @@ int GPTData::CheckHeaderValidity(void) {
|
|||||||
// Note: Must be called BEFORE byte-order reversal on big-endian
|
// Note: Must be called BEFORE byte-order reversal on big-endian
|
||||||
// systems!
|
// systems!
|
||||||
int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
||||||
uint32_t oldCRC, newCRC;
|
uint32_t oldCRC, newCRC, hSize;
|
||||||
|
|
||||||
// Back up old header CRC and then blank it, since it must be 0 for
|
// Back up old header CRC and then blank it, since it must be 0 for
|
||||||
// computation to be valid
|
// computation to be valid
|
||||||
oldCRC = header->headerCRC;
|
oldCRC = header->headerCRC;
|
||||||
if (IsLittleEndian() == 0)
|
|
||||||
ReverseBytes(&oldCRC, 4);
|
|
||||||
header->headerCRC = UINT32_C(0);
|
header->headerCRC = UINT32_C(0);
|
||||||
|
hSize = header->headerSize;
|
||||||
|
|
||||||
|
// If big-endian system, reverse byte order
|
||||||
|
if (IsLittleEndian() == 0) {
|
||||||
|
ReverseBytes(&oldCRC, 4);
|
||||||
|
} // if
|
||||||
|
|
||||||
// Initialize CRC functions...
|
// Initialize CRC functions...
|
||||||
chksum_crc32gentab();
|
chksum_crc32gentab();
|
||||||
|
|
||||||
// Compute CRC, restore original, and return result of comparison
|
// Compute CRC, restore original, and return result of comparison
|
||||||
newCRC = chksum_crc32((unsigned char*) header, HEADER_SIZE);
|
newCRC = chksum_crc32((unsigned char*) header, HEADER_SIZE);
|
||||||
mainHeader.headerCRC = oldCRC;
|
header->headerCRC = oldCRC;
|
||||||
return (oldCRC == newCRC);
|
return (oldCRC == newCRC);
|
||||||
} // GPTData::CheckHeaderCRC()
|
} // GPTData::CheckHeaderCRC()
|
||||||
|
|
||||||
// Recompute all the CRCs. Must be called before saving (but after reversing
|
// Recompute all the CRCs. Must be called before saving (but after reversing
|
||||||
// byte order on big-endian systems) if any changes have been made.
|
// byte order on big-endian systems) if any changes have been made.
|
||||||
void GPTData::RecomputeCRCs(void) {
|
void GPTData::RecomputeCRCs(void) {
|
||||||
uint32_t crc;
|
uint32_t crc, hSize, trueNumParts;
|
||||||
uint32_t trueNumParts;
|
|
||||||
int littleEndian = 1;
|
int littleEndian = 1;
|
||||||
|
|
||||||
// Initialize CRC functions...
|
// Initialize CRC functions...
|
||||||
chksum_crc32gentab();
|
chksum_crc32gentab();
|
||||||
|
|
||||||
|
hSize = mainHeader.headerSize;
|
||||||
littleEndian = IsLittleEndian();
|
littleEndian = IsLittleEndian();
|
||||||
|
|
||||||
// Compute CRC of partition tables & store in main and secondary headers
|
// Compute CRC of partition tables & store in main and secondary headers
|
||||||
@@ -342,11 +363,11 @@ void GPTData::RecomputeCRCs(void) {
|
|||||||
secondHeader.headerCRC = 0;
|
secondHeader.headerCRC = 0;
|
||||||
|
|
||||||
// Compute & store CRCs of main & secondary headers...
|
// Compute & store CRCs of main & secondary headers...
|
||||||
crc = chksum_crc32((unsigned char*) &mainHeader, HEADER_SIZE);
|
crc = chksum_crc32((unsigned char*) &mainHeader, hSize);
|
||||||
if (littleEndian == 0)
|
if (littleEndian == 0)
|
||||||
ReverseBytes(&crc, 4);
|
ReverseBytes(&crc, 4);
|
||||||
mainHeader.headerCRC = crc;
|
mainHeader.headerCRC = crc;
|
||||||
crc = chksum_crc32((unsigned char*) &secondHeader, HEADER_SIZE);
|
crc = chksum_crc32((unsigned char*) &secondHeader, hSize);
|
||||||
if (littleEndian == 0)
|
if (littleEndian == 0)
|
||||||
ReverseBytes(&crc, 4);
|
ReverseBytes(&crc, 4);
|
||||||
secondHeader.headerCRC = crc;
|
secondHeader.headerCRC = crc;
|
||||||
@@ -359,7 +380,7 @@ void GPTData::RebuildMainHeader(void) {
|
|||||||
|
|
||||||
mainHeader.signature = GPT_SIGNATURE;
|
mainHeader.signature = GPT_SIGNATURE;
|
||||||
mainHeader.revision = secondHeader.revision;
|
mainHeader.revision = secondHeader.revision;
|
||||||
mainHeader.headerSize = HEADER_SIZE;
|
mainHeader.headerSize = secondHeader.headerSize;
|
||||||
mainHeader.headerCRC = UINT32_C(0);
|
mainHeader.headerCRC = UINT32_C(0);
|
||||||
mainHeader.reserved = secondHeader.reserved;
|
mainHeader.reserved = secondHeader.reserved;
|
||||||
mainHeader.currentLBA = secondHeader.backupLBA;
|
mainHeader.currentLBA = secondHeader.backupLBA;
|
||||||
@@ -382,7 +403,7 @@ void GPTData::RebuildSecondHeader(void) {
|
|||||||
|
|
||||||
secondHeader.signature = GPT_SIGNATURE;
|
secondHeader.signature = GPT_SIGNATURE;
|
||||||
secondHeader.revision = mainHeader.revision;
|
secondHeader.revision = mainHeader.revision;
|
||||||
secondHeader.headerSize = HEADER_SIZE;
|
secondHeader.headerSize = mainHeader.headerSize;
|
||||||
secondHeader.headerCRC = UINT32_C(0);
|
secondHeader.headerCRC = UINT32_C(0);
|
||||||
secondHeader.reserved = mainHeader.reserved;
|
secondHeader.reserved = mainHeader.reserved;
|
||||||
secondHeader.currentLBA = mainHeader.backupLBA;
|
secondHeader.currentLBA = mainHeader.backupLBA;
|
||||||
@@ -486,12 +507,6 @@ void GPTData::PartitionScan(int fd) {
|
|||||||
printf("It will be destroyed if you continue!\n");
|
printf("It will be destroyed if you continue!\n");
|
||||||
printf("*******************************************************************\n\n\a");
|
printf("*******************************************************************\n\n\a");
|
||||||
} // if
|
} // if
|
||||||
/* if (bsdFound) {
|
|
||||||
printf("\n*************************************************************************\n");
|
|
||||||
printf("This disk appears to contain a BSD disklabel! It will be destroyed if you\n"
|
|
||||||
"continue!\n");
|
|
||||||
printf("*************************************************************************\n\n\a");
|
|
||||||
} // if */
|
|
||||||
} // GPTData::PartitionScan()
|
} // GPTData::PartitionScan()
|
||||||
|
|
||||||
// Read GPT data from a disk.
|
// Read GPT data from a disk.
|
||||||
@@ -703,7 +718,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(void) {
|
||||||
int allOK = 1, i;
|
int allOK = 1;
|
||||||
char answer, line[256];
|
char answer, line[256];
|
||||||
int fd;
|
int fd;
|
||||||
uint64_t secondTable;
|
uint64_t secondTable;
|
||||||
@@ -856,6 +871,12 @@ int GPTData::SaveGPTBackup(char* filename) {
|
|||||||
ReverseHeaderBytes(&secondHeader);
|
ReverseHeaderBytes(&secondHeader);
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
|
// Recomputing the CRCs is likely to alter them, which could be bad
|
||||||
|
// if the intent is to save a potentially bad GPT for later analysis;
|
||||||
|
// but if we don't do this, we get bogus errors when we load the
|
||||||
|
// backup. I'm favoring misses over false alarms....
|
||||||
|
RecomputeCRCs();
|
||||||
|
|
||||||
// Now write the protective MBR...
|
// Now write the protective MBR...
|
||||||
protectiveMBR.WriteMBRData(fd);
|
protectiveMBR.WriteMBRData(fd);
|
||||||
|
|
||||||
@@ -1021,8 +1042,8 @@ void GPTData::DisplayGPTData(void) {
|
|||||||
uint64_t temp, totalFree;
|
uint64_t temp, totalFree;
|
||||||
|
|
||||||
BytesToSI(diskSize * blockSize, sizeInSI);
|
BytesToSI(diskSize * blockSize, sizeInSI);
|
||||||
printf("Disk %s: %lu sectors, %s\n", device,
|
printf("Disk %s: %llu sectors, %s\n", device,
|
||||||
(unsigned long) diskSize, sizeInSI);
|
(unsigned long long) diskSize, sizeInSI);
|
||||||
printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr));
|
printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr));
|
||||||
printf("Partition table holds up to %lu entries\n", (unsigned long) mainHeader.numParts);
|
printf("Partition table holds up to %lu entries\n", (unsigned long) mainHeader.numParts);
|
||||||
printf("First usable sector is %lu, last usable sector is %lu\n",
|
printf("First usable sector is %lu, last usable sector is %lu\n",
|
||||||
@@ -1033,7 +1054,7 @@ void GPTData::DisplayGPTData(void) {
|
|||||||
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
|
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
|
||||||
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
|
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
partitions[i].ShowSummary(i, blockSize, sizeInSI);
|
partitions[i].ShowSummary(i, blockSize);
|
||||||
} // for
|
} // for
|
||||||
} // GPTData::DisplayGPTData()
|
} // GPTData::DisplayGPTData()
|
||||||
|
|
||||||
@@ -1212,20 +1233,24 @@ void GPTData::SetAttributes(uint32_t partNum) {
|
|||||||
|
|
||||||
// This function destroys the on-disk GPT structures. Returns 1 if the
|
// This function destroys the on-disk GPT structures. Returns 1 if the
|
||||||
// user confirms destruction, 0 if the user aborts.
|
// user confirms destruction, 0 if the user aborts.
|
||||||
int GPTData::DestroyGPT(void) {
|
// 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.)
|
||||||
|
int GPTData::DestroyGPT(int prompt) {
|
||||||
int fd, i;
|
int fd, i;
|
||||||
char blankSector[512], goOn;
|
char blankSector[512], goOn = 'Y', blank = 'N';
|
||||||
|
|
||||||
for (i = 0; i < 512; i++) {
|
for (i = 0; i < 512; i++) {
|
||||||
blankSector[i] = '\0';
|
blankSector[i] = '\0';
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
if ((apmFound) || (bsdFound)) {
|
if (((apmFound) || (bsdFound)) && prompt) {
|
||||||
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
|
||||||
printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
|
if (prompt) {
|
||||||
goOn = GetYN();
|
printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
|
||||||
|
goOn = GetYN();
|
||||||
|
} // if
|
||||||
if (goOn == 'Y') {
|
if (goOn == 'Y') {
|
||||||
fd = open(device, O_WRONLY);
|
fd = open(device, O_WRONLY);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@@ -1245,18 +1270,21 @@ int GPTData::DestroyGPT(void) {
|
|||||||
write(fd, blankSector, 512);
|
write(fd, blankSector, 512);
|
||||||
lseek64(fd, secondHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
|
lseek64(fd, secondHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
|
||||||
write(fd, blankSector, 512); // blank it out
|
write(fd, blankSector, 512); // blank it out
|
||||||
printf("Blank out MBR? ");
|
if (prompt) {
|
||||||
if (GetYN() == 'Y') {
|
printf("Blank out MBR? ");
|
||||||
|
blank = GetYN();
|
||||||
|
}// 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') {
|
||||||
lseek64(fd, 0, SEEK_SET);
|
lseek64(fd, 0, SEEK_SET);
|
||||||
write(fd, blankSector, 512); // blank it out
|
write(fd, blankSector, 512); // blank it out
|
||||||
} else { // write current protective MBR, in case it's hybrid....
|
} else {
|
||||||
// find and delete 0xEE partitions in MBR
|
printf("MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n"
|
||||||
for (i = 0; i < 4; i++) {
|
"with fdisk or another tool.\n");
|
||||||
if (protectiveMBR.GetType(i) == (uint8_t) 0xEE) {
|
|
||||||
protectiveMBR.DeletePartition(i);
|
|
||||||
} // if
|
|
||||||
} // for
|
|
||||||
protectiveMBR.WriteMBRData(fd);
|
|
||||||
} // if/else
|
} // if/else
|
||||||
DiskSync(fd);
|
DiskSync(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -1374,8 +1402,8 @@ int GPTData::XFormPartitions(void) {
|
|||||||
ClearGPTData();
|
ClearGPTData();
|
||||||
|
|
||||||
// Convert the smaller of the # of GPT or MBR partitions
|
// Convert the smaller of the # of GPT or MBR partitions
|
||||||
if (mainHeader.numParts > (NUM_LOGICALS + 4))
|
if (mainHeader.numParts > (MAX_MBR_PARTS))
|
||||||
numToConvert = NUM_LOGICALS + 4;
|
numToConvert = MAX_MBR_PARTS;
|
||||||
else
|
else
|
||||||
numToConvert = mainHeader.numParts;
|
numToConvert = mainHeader.numParts;
|
||||||
|
|
||||||
@@ -1467,15 +1495,102 @@ int GPTData::XFormDisklabel(BSDData* disklabel, int startPart) {
|
|||||||
return numDone;
|
return numDone;
|
||||||
} // GPTData::XFormDisklabel(BSDData* disklabel)
|
} // GPTData::XFormDisklabel(BSDData* disklabel)
|
||||||
|
|
||||||
|
// Add one GPT partition to MBR. Used by XFormToMBR() and MakeHybrid()
|
||||||
|
// functions. Returns 1 if operation was successful.
|
||||||
|
int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
||||||
|
int allOK = 1, typeCode, bootable;
|
||||||
|
uint64_t length;
|
||||||
|
char line[255];
|
||||||
|
|
||||||
|
if ((mbrPart < 0) || (mbrPart > 3)) {
|
||||||
|
printf("MBR partition %d is out of range; omitting it.\n", mbrPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
if (gptPart >= mainHeader.numParts) {
|
||||||
|
printf("GPT partition %d is out of range; omitting it.\n", gptPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
if (allOK && (partitions[gptPart].GetLastLBA() == UINT64_C(0))) {
|
||||||
|
printf("GPT partition %d is undefined; omitting it.\n", gptPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
if (allOK && (partitions[gptPart].GetFirstLBA() <= UINT32_MAX) &&
|
||||||
|
(partitions[gptPart].GetLengthLBA() <= UINT32_MAX)) {
|
||||||
|
if (partitions[gptPart].GetLastLBA() > UINT32_MAX) {
|
||||||
|
printf("Caution: Partition end point past 32-bit pointer boundary;"
|
||||||
|
" some OSes may\nreact strangely.\n");
|
||||||
|
} // if partition ends past 32-bit (usually 2TiB) boundary
|
||||||
|
do {
|
||||||
|
printf("Enter an MBR hex code (default %02X): ",
|
||||||
|
typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256);
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
sscanf(line, "%x", &typeCode);
|
||||||
|
if (line[0] == '\n')
|
||||||
|
typeCode = partitions[gptPart].GetHexType() / 256;
|
||||||
|
} while ((typeCode <= 0) || (typeCode > 255));
|
||||||
|
printf("Set the bootable flag? ");
|
||||||
|
bootable = (GetYN() == 'Y');
|
||||||
|
length = partitions[gptPart].GetLengthLBA();
|
||||||
|
protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(),
|
||||||
|
(uint32_t) length, typeCode, bootable);
|
||||||
|
} else { // partition out of range
|
||||||
|
printf("Partition %d begins beyond the 32-bit pointer limit of MBR "
|
||||||
|
"partitions, or is\n too big; omitting it.\n", gptPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if/else
|
||||||
|
return allOK;
|
||||||
|
} // GPTData::OnePartToMBR()
|
||||||
|
|
||||||
|
// Convert the GPT to MBR form. This function is necessarily limited; it
|
||||||
|
// handles at most four partitions and creates layouts that ignore CHS
|
||||||
|
// geometries. Returns the number of converted partitions; if this value
|
||||||
|
// is over 0, the calling function should call DestroyGPT() to destroy
|
||||||
|
// the GPT data, and then exit.
|
||||||
|
int GPTData::XFormToMBR(void) {
|
||||||
|
char line[255];
|
||||||
|
int i, j, numParts, numConverted = 0;
|
||||||
|
uint32_t partNums[4];
|
||||||
|
|
||||||
|
// Get the numbers of up to four partitions to add to the
|
||||||
|
// hybrid MBR....
|
||||||
|
numParts = CountParts();
|
||||||
|
printf("Counted %d partitions.\n", numParts);
|
||||||
|
|
||||||
|
// Prepare the MBR for conversion (empty it of existing partitions).
|
||||||
|
protectiveMBR.EmptyMBR(0);
|
||||||
|
protectiveMBR.SetDiskSize(diskSize);
|
||||||
|
|
||||||
|
if (numParts > 4) { // Over four partitions; engage in triage
|
||||||
|
printf("Type from one to four GPT partition numbers, separated by spaces, to be\n"
|
||||||
|
"used in the MBR, in sequence: ");
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
numParts = sscanf(line, "%d %d %d %d", &partNums[0], &partNums[1],
|
||||||
|
&partNums[2], &partNums[3]);
|
||||||
|
} else { // Four or fewer partitions; convert them all
|
||||||
|
i = j = 0;
|
||||||
|
while ((j < numParts) && (i < mainHeader.numParts)) {
|
||||||
|
if (partitions[i].GetFirstLBA() > 0) { // if GPT part. is defined
|
||||||
|
partNums[j++] = ++i; // flag it for conversion
|
||||||
|
} else i++;
|
||||||
|
} // while
|
||||||
|
} // if/else
|
||||||
|
|
||||||
|
for (i = 0; i < numParts; i++) {
|
||||||
|
j = partNums[i] - 1;
|
||||||
|
printf("\nCreating entry for partition #%d\n", j + 1);
|
||||||
|
numConverted += OnePartToMBR(j, i);
|
||||||
|
} // for
|
||||||
|
return numConverted;
|
||||||
|
} // GPTData::XFormToMBR()
|
||||||
|
|
||||||
// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with
|
// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with
|
||||||
// OSes that don't understand GPT.
|
// OSes that don't understand GPT.
|
||||||
void GPTData::MakeHybrid(void) {
|
void GPTData::MakeHybrid(void) {
|
||||||
uint32_t partNums[3];
|
uint32_t partNums[3];
|
||||||
char line[255];
|
char line[255];
|
||||||
int numParts, i, j, typeCode, bootable, mbrNum;
|
int numParts, numConverted = 0, i, j, typeCode, mbrNum;
|
||||||
uint64_t length;
|
|
||||||
char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe)
|
char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe)
|
||||||
char eeFirst; // Whether EFI GPT (0xEE) partition comes first in table
|
char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
|
||||||
|
|
||||||
printf("\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n"
|
printf("\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n"
|
||||||
"to use one, just hit the Enter key at the below prompt and your MBR\n"
|
"to use one, just hit the Enter key at the below prompt and your MBR\n"
|
||||||
@@ -1500,38 +1615,14 @@ void GPTData::MakeHybrid(void) {
|
|||||||
for (i = 0; i < numParts; i++) {
|
for (i = 0; i < numParts; i++) {
|
||||||
j = partNums[i] - 1;
|
j = partNums[i] - 1;
|
||||||
printf("\nCreating entry for partition #%d\n", j + 1);
|
printf("\nCreating entry for partition #%d\n", j + 1);
|
||||||
if ((j >= 0) && (j < mainHeader.numParts)) {
|
if (eeFirst == 'Y')
|
||||||
if ((partitions[j].GetLastLBA() < UINT32_MAX) &&
|
mbrNum = i + 1;
|
||||||
(partitions[j].GetLastLBA() > UINT64_C(0))) {
|
else
|
||||||
do {
|
mbrNum = i;
|
||||||
printf("Enter an MBR hex code (default %02X): ",
|
numConverted += OnePartToMBR(j, mbrNum);
|
||||||
typeHelper.GUIDToID(partitions[j].GetType()) / 256);
|
|
||||||
fgets(line, 255, stdin);
|
|
||||||
sscanf(line, "%x", &typeCode);
|
|
||||||
if (line[0] == '\n')
|
|
||||||
typeCode = partitions[j].GetHexType() / 256;
|
|
||||||
} while ((typeCode <= 0) || (typeCode > 255));
|
|
||||||
printf("Set the bootable flag? ");
|
|
||||||
bootable = (GetYN() == 'Y');
|
|
||||||
length = partitions[j].GetLengthLBA();
|
|
||||||
if (eeFirst == 'Y')
|
|
||||||
mbrNum = i + 1;
|
|
||||||
else
|
|
||||||
mbrNum = i;
|
|
||||||
protectiveMBR.MakePart(mbrNum, (uint32_t) partitions[j].GetFirstLBA(),
|
|
||||||
(uint32_t) length, typeCode, bootable);
|
|
||||||
protectiveMBR.SetHybrid();
|
|
||||||
} else { // partition out of range
|
|
||||||
printf("Partition %d ends beyond the 2TiB limit of MBR partitions or does not exist;\n"
|
|
||||||
"omitting it.\n",
|
|
||||||
j + 1);
|
|
||||||
} // if/else
|
|
||||||
} else {
|
|
||||||
printf("Partition %d is out of range; omitting it.\n", j + 1);
|
|
||||||
} // if/else
|
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
if (numParts > 0) { // User opted to create a hybrid MBR....
|
if ((numParts > 0) && (numConverted > 0)) { // User opted to create a hybrid MBR....
|
||||||
// Create EFI protective partition that covers the start of the disk.
|
// Create EFI protective partition that covers the start of the disk.
|
||||||
// If this location (covering the main GPT data structures) is omitted,
|
// If this location (covering the main GPT data structures) is omitted,
|
||||||
// Linux won't find any partitions on the disk. Note that this is
|
// Linux won't find any partitions on the disk. Note that this is
|
||||||
@@ -1544,6 +1635,7 @@ void GPTData::MakeHybrid(void) {
|
|||||||
else
|
else
|
||||||
mbrNum = numParts;
|
mbrNum = numParts;
|
||||||
protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), 0xEE);
|
protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), 0xEE);
|
||||||
|
protectiveMBR.SetHybrid();
|
||||||
|
|
||||||
// ... and for good measure, if there are any partition spaces left,
|
// ... and for good measure, if there are any partition spaces left,
|
||||||
// optionally create another protective EFI partition to cover as much
|
// optionally create another protective EFI partition to cover as much
|
||||||
@@ -1692,7 +1784,7 @@ int GPTData::ClearGPTData(void) {
|
|||||||
// Now initialize a bunch of stuff that's static....
|
// Now initialize a bunch of stuff that's static....
|
||||||
mainHeader.signature = GPT_SIGNATURE;
|
mainHeader.signature = GPT_SIGNATURE;
|
||||||
mainHeader.revision = 0x00010000;
|
mainHeader.revision = 0x00010000;
|
||||||
mainHeader.headerSize = (uint32_t) HEADER_SIZE;
|
mainHeader.headerSize = HEADER_SIZE;
|
||||||
mainHeader.reserved = 0;
|
mainHeader.reserved = 0;
|
||||||
mainHeader.currentLBA = UINT64_C(1);
|
mainHeader.currentLBA = UINT64_C(1);
|
||||||
mainHeader.partitionEntriesLBA = (uint64_t) 2;
|
mainHeader.partitionEntriesLBA = (uint64_t) 2;
|
||||||
@@ -1790,6 +1882,17 @@ int GPTData::GetPartRange(uint32_t *low, uint32_t *high) {
|
|||||||
return numFound;
|
return numFound;
|
||||||
} // GPTData::GetPartRange()
|
} // GPTData::GetPartRange()
|
||||||
|
|
||||||
|
// Returns the number of defined partitions.
|
||||||
|
uint32_t GPTData::CountParts(void) {
|
||||||
|
int i, counted = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
|
if (partitions[i].GetFirstLBA() > 0)
|
||||||
|
counted++;
|
||||||
|
} // for
|
||||||
|
return counted;
|
||||||
|
} // GPTData::CountParts()
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* *
|
* *
|
||||||
* Functions that return data about disk free space *
|
* Functions that return data about disk free space *
|
||||||
@@ -2017,8 +2120,8 @@ int SizesOK(void) {
|
|||||||
fprintf(stderr, "MBRRecord is %d bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord));
|
fprintf(stderr, "MBRRecord is %d bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord));
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
if (sizeof(struct EBRRecord) != 512) {
|
if (sizeof(struct TempMBR) != 512) {
|
||||||
fprintf(stderr, "EBRRecord is %d bytes, should be 512 bytes; aborting!\n", sizeof(EBRRecord));
|
fprintf(stderr, "TempMBR is %d bytes, should be 512 bytes; aborting!\n", sizeof(TempMBR));
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
if (sizeof(struct GPTHeader) != 512) {
|
if (sizeof(struct GPTHeader) != 512) {
|
||||||
|
|||||||
10
gpt.h
10
gpt.h
@@ -67,7 +67,6 @@ protected:
|
|||||||
int secondPartsCrcOk;
|
int secondPartsCrcOk;
|
||||||
int apmFound; // set to 1 if APM detected
|
int apmFound; // set to 1 if APM detected
|
||||||
int bsdFound; // set to 1 if BSD disklabel detected in MBR
|
int bsdFound; // set to 1 if BSD disklabel detected in MBR
|
||||||
// uint32_t units; // display units, in multiples of sectors
|
|
||||||
PartTypes typeHelper;
|
PartTypes typeHelper;
|
||||||
public:
|
public:
|
||||||
// Basic necessary functions....
|
// Basic necessary functions....
|
||||||
@@ -87,6 +86,7 @@ public:
|
|||||||
int FindOverlaps(void);
|
int FindOverlaps(void);
|
||||||
|
|
||||||
// Load or save data from/to disk
|
// Load or save data from/to disk
|
||||||
|
int LoadMBR(char* f) {return protectiveMBR.ReadMBRData(f);}
|
||||||
void PartitionScan(int fd);
|
void PartitionScan(int fd);
|
||||||
int LoadPartitions(char* deviceFilename);
|
int LoadPartitions(char* deviceFilename);
|
||||||
int ForceLoadGPTData(int fd);
|
int ForceLoadGPTData(int fd);
|
||||||
@@ -111,13 +111,15 @@ public:
|
|||||||
void DeletePartition(void);
|
void DeletePartition(void);
|
||||||
void ChangePartType(void);
|
void ChangePartType(void);
|
||||||
void SetAttributes(uint32_t partNum);
|
void SetAttributes(uint32_t partNum);
|
||||||
int DestroyGPT(void); // Returns 1 if user proceeds
|
int DestroyGPT(int prompt = 1); // Returns 1 if user proceeds
|
||||||
|
|
||||||
// Convert to GPT from other formats (may require user interaction)
|
// Convert between GPT and other formats (may require user interaction)
|
||||||
WhichToUse UseWhichPartitions(void);
|
WhichToUse UseWhichPartitions(void);
|
||||||
int XFormPartitions(void);
|
int XFormPartitions(void);
|
||||||
int XFormDisklabel(int OnGptPart = -1);
|
int XFormDisklabel(int OnGptPart = -1);
|
||||||
int XFormDisklabel(BSDData* disklabel, int startPart);
|
int XFormDisklabel(BSDData* disklabel, int startPart);
|
||||||
|
int OnePartToMBR(uint32_t gptPart, int mbrPart); // add one partition to MBR. Returns 1 if successful
|
||||||
|
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
|
||||||
void MakeHybrid(void);
|
void MakeHybrid(void);
|
||||||
|
|
||||||
// Adjust GPT structures WITHOUT user interaction...
|
// Adjust GPT structures WITHOUT user interaction...
|
||||||
@@ -139,6 +141,8 @@ public:
|
|||||||
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
|
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
|
||||||
uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
|
uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
|
||||||
mainHeader.sizeOfPartitionEntries) / blockSize;}
|
mainHeader.sizeOfPartitionEntries) / blockSize;}
|
||||||
|
uint32_t CountParts(void);
|
||||||
|
|
||||||
|
|
||||||
// Find information about free space
|
// Find information about free space
|
||||||
uint64_t FindFirstAvailable(uint64_t start = 0);
|
uint64_t FindFirstAvailable(uint64_t start = 0);
|
||||||
|
|||||||
16
gptpart.cc
16
gptpart.cc
@@ -9,8 +9,8 @@
|
|||||||
// Copyright: See COPYING file that comes with this distribution
|
// Copyright: See COPYING file that comes with this distribution
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
||||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
|
||||||
|
|
||||||
#define __STDC_LIMIT_MACROS
|
#define __STDC_LIMIT_MACROS
|
||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
@@ -25,6 +25,10 @@ using namespace std;
|
|||||||
PartTypes GPTPart::typeHelper;
|
PartTypes GPTPart::typeHelper;
|
||||||
|
|
||||||
GPTPart::GPTPart(void) {
|
GPTPart::GPTPart(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NAME_SIZE; i++)
|
||||||
|
name[i] = '\0';
|
||||||
} // Default constructor
|
} // Default constructor
|
||||||
|
|
||||||
GPTPart::~GPTPart(void) {
|
GPTPart::~GPTPart(void) {
|
||||||
@@ -128,16 +132,16 @@ void GPTPart::ReversePartBytes(void) {
|
|||||||
} // GPTPart::ReverseBytes()
|
} // GPTPart::ReverseBytes()
|
||||||
|
|
||||||
// Display summary information; does nothing if the partition is empty.
|
// Display summary information; does nothing if the partition is empty.
|
||||||
void GPTPart::ShowSummary(int i, uint32_t blockSize, char* sizeInSI) {
|
void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
|
||||||
int j;
|
char sizeInSI[255];
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
if (firstLBA != 0) {
|
if (firstLBA != 0) {
|
||||||
BytesToSI(blockSize * (lastLBA - firstLBA + 1), sizeInSI);
|
BytesToSI(blockSize * (lastLBA - firstLBA + 1), sizeInSI);
|
||||||
printf("%4d %14lu %14lu", i + 1, (unsigned long) firstLBA,
|
printf("%4d %14lu %14lu", partNum + 1, (unsigned long) firstLBA,
|
||||||
(unsigned long) lastLBA);
|
(unsigned long) lastLBA);
|
||||||
printf(" %-10s %04X ", sizeInSI,
|
printf(" %-10s %04X ", sizeInSI,
|
||||||
typeHelper.GUIDToID(partitionType));
|
typeHelper.GUIDToID(partitionType));
|
||||||
j = 0;
|
|
||||||
while ((name[j] != '\0') && (j < 44)) {
|
while ((name[j] != '\0') && (j < 44)) {
|
||||||
printf("%c", name[j]);
|
printf("%c", name[j]);
|
||||||
j += 2;
|
j += 2;
|
||||||
|
|||||||
16
gptpart.h
16
gptpart.h
@@ -9,8 +9,8 @@
|
|||||||
// Copyright: See COPYING file that comes with this distribution
|
// Copyright: See COPYING file that comes with this distribution
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
||||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
|
||||||
|
|
||||||
#ifndef __GPTPART_H
|
#ifndef __GPTPART_H
|
||||||
#define __GPTPART_H
|
#define __GPTPART_H
|
||||||
@@ -23,11 +23,11 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
/*****************************************
|
/****************************************
|
||||||
* *
|
* *
|
||||||
* GUIDPart class and related structures *
|
* GPTPart class and related structures *
|
||||||
* *
|
* *
|
||||||
*****************************************/
|
****************************************/
|
||||||
|
|
||||||
class GPTPart {
|
class GPTPart {
|
||||||
protected:
|
protected:
|
||||||
@@ -73,7 +73,7 @@ class GPTPart {
|
|||||||
|
|
||||||
// Additional functions
|
// Additional functions
|
||||||
GPTPart & operator=(const GPTPart & orig);
|
GPTPart & operator=(const GPTPart & orig);
|
||||||
void ShowSummary(int i, uint32_t blockSize, char* sizeInSI); // display summary information (1-line)
|
void ShowSummary(int partNum, uint32_t blockSize); // display summary information (1-line)
|
||||||
void ShowDetails(uint32_t blockSize); // display detailed information (multi-line)
|
void ShowDetails(uint32_t blockSize); // display detailed information (multi-line)
|
||||||
void BlankPartition(void); // empty partition of data
|
void BlankPartition(void); // empty partition of data
|
||||||
int DoTheyOverlap(GPTPart* other); // returns 1 if there's overlap
|
int DoTheyOverlap(GPTPart* other); // returns 1 if there's overlap
|
||||||
|
|||||||
568
mbr.cc
568
mbr.cc
@@ -1,7 +1,7 @@
|
|||||||
/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
|
/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
|
||||||
data. */
|
data. */
|
||||||
|
|
||||||
/* By Rod Smith, January to February, 2009 */
|
/* Initial coding by Rod Smith, January to February, 2009 */
|
||||||
|
|
||||||
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
||||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
||||||
@@ -35,6 +35,8 @@ MBRData::MBRData(void) {
|
|||||||
strcpy(device, "");
|
strcpy(device, "");
|
||||||
state = invalid;
|
state = invalid;
|
||||||
srand((unsigned int) time(NULL));
|
srand((unsigned int) time(NULL));
|
||||||
|
numHeads = MAX_HEADS;
|
||||||
|
numSecspTrack = MAX_SECSPERTRACK;
|
||||||
EmptyMBR();
|
EmptyMBR();
|
||||||
} // MBRData default constructor
|
} // MBRData default constructor
|
||||||
|
|
||||||
@@ -43,6 +45,8 @@ MBRData::MBRData(char *filename) {
|
|||||||
diskSize = 0;
|
diskSize = 0;
|
||||||
strcpy(device, filename);
|
strcpy(device, filename);
|
||||||
state = invalid;
|
state = invalid;
|
||||||
|
numHeads = MAX_HEADS;
|
||||||
|
numSecspTrack = MAX_SECSPERTRACK;
|
||||||
|
|
||||||
srand((unsigned int) time(NULL));
|
srand((unsigned int) time(NULL));
|
||||||
// Try to read the specified partition table, but if it fails....
|
// Try to read the specified partition table, but if it fails....
|
||||||
@@ -55,51 +59,11 @@ MBRData::MBRData(char *filename) {
|
|||||||
MBRData::~MBRData(void) {
|
MBRData::~MBRData(void) {
|
||||||
} // MBRData destructor
|
} // MBRData destructor
|
||||||
|
|
||||||
// Empty all data. Meant mainly for calling by constructors, but it's also
|
/**********************
|
||||||
// used by the hybrid MBR functions in the GPTData class.
|
* *
|
||||||
void MBRData::EmptyMBR(int clearBootloader) {
|
* Disk I/O functions *
|
||||||
int i;
|
* *
|
||||||
|
**********************/
|
||||||
// Zero out the boot loader section, the disk signature, and the
|
|
||||||
// 2-byte nulls area only if requested to do so. (This is the
|
|
||||||
// default.)
|
|
||||||
if (clearBootloader == 1) {
|
|
||||||
for (i = 0; i < 440; i++)
|
|
||||||
code[i] = 0;
|
|
||||||
diskSignature = (uint32_t) rand();
|
|
||||||
nulls = 0;
|
|
||||||
} // if
|
|
||||||
|
|
||||||
// Blank out the partitions
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
partitions[i].status = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].partitionType = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].firstLBA = UINT32_C(0);
|
|
||||||
partitions[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
MBRSignature = MBR_SIGNATURE;
|
|
||||||
|
|
||||||
blockSize = SECTOR_SIZE;
|
|
||||||
diskSize = 0;
|
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
|
||||||
logicals[i].status = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].partitionType = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].firstLBA = UINT32_C(0);
|
|
||||||
logicals[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
} // MBRData::EmptyMBR()
|
|
||||||
|
|
||||||
// Read data from MBR. Returns 1 if read was successful (even if the
|
// Read data from MBR. Returns 1 if read was successful (even if the
|
||||||
// data isn't a valid MBR), 0 if the read failed.
|
// data isn't a valid MBR), 0 if the read failed.
|
||||||
@@ -120,25 +84,18 @@ int MBRData::ReadMBRData(char* deviceFilename) {
|
|||||||
return allOK;
|
return allOK;
|
||||||
} // MBRData::ReadMBRData(char* deviceFilename)
|
} // MBRData::ReadMBRData(char* deviceFilename)
|
||||||
|
|
||||||
// Read data from MBR.
|
// Read data from MBR. If checkBlockSize == 1 (the default), the block
|
||||||
|
// size is checked; otherwise it's set to the default (512 bytes).
|
||||||
|
// Note that any extended partition(s) present will be explicitly stored
|
||||||
|
// in the partitions[] array, along with their contained partitions; the
|
||||||
|
// extended container partition(s) should be ignored by other functions.
|
||||||
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
||||||
int allOK = 1, i, j, maxLogicals = 0;
|
int allOK = 1, i, j, logicalNum;
|
||||||
int err;
|
int err;
|
||||||
TempMBR tempMBR;
|
TempMBR tempMBR;
|
||||||
|
|
||||||
// Clear logical partition array
|
// Empty existing MBR data, including the logical partitions...
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
EmptyMBR(0);
|
||||||
logicals[i].status = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].partitionType = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].firstLBA = UINT32_C(0);
|
|
||||||
logicals[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
err = lseek64(fd, 0, SEEK_SET);
|
err = lseek64(fd, 0, SEEK_SET);
|
||||||
err = read(fd, &tempMBR, 512);
|
err = read(fd, &tempMBR, 512);
|
||||||
@@ -154,8 +111,8 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
|||||||
for (j = 0; j < 3; j++) {
|
for (j = 0; j < 3; j++) {
|
||||||
partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
|
partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
|
||||||
partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
|
partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
|
||||||
} // for j...
|
} // for j... (reading parts of CHS geometry)
|
||||||
} // for i...
|
} // for i... (reading all four partitions)
|
||||||
MBRSignature = tempMBR.MBRSignature;
|
MBRSignature = tempMBR.MBRSignature;
|
||||||
|
|
||||||
// Reverse the byte order, if necessary
|
// Reverse the byte order, if necessary
|
||||||
@@ -180,21 +137,16 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
|||||||
// Find block size
|
// Find block size
|
||||||
if (checkBlockSize) {
|
if (checkBlockSize) {
|
||||||
blockSize = GetBlockSize(fd);
|
blockSize = GetBlockSize(fd);
|
||||||
// if ((blockSize = GetBlockSize(fd)) == -1) {
|
|
||||||
// blockSize = SECTOR_SIZE;
|
|
||||||
// printf("Unable to determine sector size; assuming %lu bytes!\n",
|
|
||||||
// (unsigned long) SECTOR_SIZE);
|
|
||||||
// } // if
|
|
||||||
} // if (checkBlockSize)
|
} // if (checkBlockSize)
|
||||||
|
|
||||||
// Load logical partition data, if any is found....
|
// Load logical partition data, if any is found....
|
||||||
if (allOK) {
|
if (allOK) {
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
|
if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
|
||||||
|| (partitions[i].partitionType == 0x85)) {
|
|| (partitions[i].partitionType == 0x85)) {
|
||||||
// Found it, so call a recursive algorithm to load everything from them....
|
// Found it, so call a recursive algorithm to load everything from them....
|
||||||
maxLogicals = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), maxLogicals);
|
logicalNum = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), 4);
|
||||||
if ((maxLogicals < 0) || (maxLogicals > NUM_LOGICALS)) {
|
if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
|
fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
|
||||||
} // if maxLogicals valid
|
} // if maxLogicals valid
|
||||||
@@ -224,26 +176,70 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
|||||||
(partitions[i].partitionType != UINT8_C(0x00)))
|
(partitions[i].partitionType != UINT8_C(0x00)))
|
||||||
state = hybrid;
|
state = hybrid;
|
||||||
} // for
|
} // for
|
||||||
} // if hybrid
|
} // if (hybrid detection code)
|
||||||
|
|
||||||
/* // Tell the user what the MBR state is...
|
|
||||||
switch (state) {
|
|
||||||
case invalid:
|
|
||||||
printf("Information: MBR appears to be empty or invalid.\n");
|
|
||||||
break;
|
|
||||||
case gpt:
|
|
||||||
printf("Information: MBR holds GPT placeholder partitions.\n");
|
|
||||||
break;
|
|
||||||
case hybrid:
|
|
||||||
printf("Information: MBR holds hybrid GPT/MBR data.\n");
|
|
||||||
break;
|
|
||||||
case mbr:
|
|
||||||
printf("Information: MBR data appears to be valid.\n");
|
|
||||||
break;
|
|
||||||
} // switch */
|
|
||||||
} // MBRData::ReadMBRData(int fd)
|
} // MBRData::ReadMBRData(int fd)
|
||||||
|
|
||||||
// Write the MBR data to the default defined device.
|
// This is a recursive function to read all the logical partitions, following the
|
||||||
|
// logical partition linked list from the disk and storing the basic data in the
|
||||||
|
// partitions[] array. Returns last index to partitions[] used, or -1 if there was
|
||||||
|
// a problem.
|
||||||
|
// Parameters:
|
||||||
|
// fd = file descriptor
|
||||||
|
// extendedStart = LBA of the start of the extended partition
|
||||||
|
// diskOffset = LBA offset WITHIN the extended partition of the one to be read
|
||||||
|
// partNum = location in partitions[] array to store retrieved data
|
||||||
|
int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
|
||||||
|
uint32_t diskOffset, int partNum) {
|
||||||
|
struct TempMBR ebr;
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
// Check for a valid partition number. Note that partitions MAY be read into
|
||||||
|
// the area normally used by primary partitions, although the only calling
|
||||||
|
// function as of GPT fdisk version 0.5.0 doesn't do so.
|
||||||
|
if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
|
||||||
|
offset = (off_t) (extendedStart + diskOffset) * blockSize;
|
||||||
|
if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
|
||||||
|
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
|
||||||
|
partNum = -1;
|
||||||
|
}
|
||||||
|
if (read(fd, &ebr, 512) != 512) { // Load the data....
|
||||||
|
fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
|
||||||
|
(unsigned long) offset);
|
||||||
|
partNum = -1;
|
||||||
|
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
|
||||||
|
ReverseBytes(&ebr.MBRSignature, 2);
|
||||||
|
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
|
||||||
|
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
|
||||||
|
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
|
||||||
|
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
|
||||||
|
} // if/else/if
|
||||||
|
|
||||||
|
if (ebr.MBRSignature != MBR_SIGNATURE) {
|
||||||
|
partNum = -1;
|
||||||
|
fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
|
||||||
|
(unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
|
||||||
|
} // if
|
||||||
|
|
||||||
|
// Copy over the basic data....
|
||||||
|
partitions[partNum].status = ebr.partitions[0].status;
|
||||||
|
partitions[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
|
||||||
|
partitions[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
|
||||||
|
partitions[partNum].partitionType = ebr.partitions[0].partitionType;
|
||||||
|
|
||||||
|
// Find the next partition (if there is one) and recurse....
|
||||||
|
if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 4) &&
|
||||||
|
(partNum < (MAX_MBR_PARTS - 1))) {
|
||||||
|
partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
|
||||||
|
partNum + 1);
|
||||||
|
} else {
|
||||||
|
partNum++;
|
||||||
|
} // if another partition
|
||||||
|
} // Not enough space for all the logicals (or previous error encountered)
|
||||||
|
return (partNum);
|
||||||
|
} // MBRData::ReadLogicalPart()
|
||||||
|
|
||||||
|
// Write the MBR data to the default defined device. Note that this writes
|
||||||
|
// ONLY the MBR itself, not the logical partition data.
|
||||||
int MBRData::WriteMBRData(void) {
|
int MBRData::WriteMBRData(void) {
|
||||||
int allOK = 1, fd;
|
int allOK = 1, fd;
|
||||||
|
|
||||||
@@ -295,12 +291,6 @@ void MBRData::WriteMBRData(int fd) {
|
|||||||
lseek64(fd, 0, SEEK_SET);
|
lseek64(fd, 0, SEEK_SET);
|
||||||
write(fd, &tempMBR, 512);
|
write(fd, &tempMBR, 512);
|
||||||
|
|
||||||
/* write(fd, code, 440);
|
|
||||||
write(fd, &diskSignature, 4);
|
|
||||||
write(fd, &nulls, 2);
|
|
||||||
write(fd, partitions, 64);
|
|
||||||
write(fd, &MBRSignature, 2); */
|
|
||||||
|
|
||||||
// Reverse the byte order back, if necessary
|
// Reverse the byte order back, if necessary
|
||||||
if (IsLittleEndian() == 0) {
|
if (IsLittleEndian() == 0) {
|
||||||
ReverseBytes(&diskSignature, 4);
|
ReverseBytes(&diskSignature, 4);
|
||||||
@@ -313,56 +303,11 @@ void MBRData::WriteMBRData(int fd) {
|
|||||||
}// if
|
}// if
|
||||||
} // MBRData::WriteMBRData(int fd)
|
} // MBRData::WriteMBRData(int fd)
|
||||||
|
|
||||||
// This is a recursive function to read all the logical partitions, following the
|
/********************************************
|
||||||
// logical partition linked list from the disk and storing the basic data in the
|
* *
|
||||||
// logicals[] array. Returns last index to logicals[] uses, or -1 if there was a
|
* Functions that display data for the user *
|
||||||
// problem
|
* *
|
||||||
int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
|
********************************************/
|
||||||
uint32_t diskOffset, int partNum) {
|
|
||||||
struct EBRRecord ebr;
|
|
||||||
off_t offset;
|
|
||||||
|
|
||||||
if ((partNum < NUM_LOGICALS) && (partNum >= 0)) {
|
|
||||||
offset = (off_t) (extendedStart + diskOffset) * blockSize;
|
|
||||||
if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
|
|
||||||
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
|
|
||||||
partNum = -1;
|
|
||||||
}
|
|
||||||
if (read(fd, &ebr, 512) != 512) { // Load the data....
|
|
||||||
fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
|
|
||||||
(unsigned long) offset);
|
|
||||||
partNum = -1;
|
|
||||||
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
|
|
||||||
ReverseBytes(&ebr.MBRSignature, 2);
|
|
||||||
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
|
|
||||||
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
|
|
||||||
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
|
|
||||||
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
|
|
||||||
} // if/else/if
|
|
||||||
|
|
||||||
if (ebr.MBRSignature != MBR_SIGNATURE) {
|
|
||||||
partNum = -1;
|
|
||||||
fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
|
|
||||||
(unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
|
|
||||||
} // if
|
|
||||||
|
|
||||||
// Copy over the basic data....
|
|
||||||
logicals[partNum].status = ebr.partitions[0].status;
|
|
||||||
logicals[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
|
|
||||||
logicals[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
|
|
||||||
logicals[partNum].partitionType = ebr.partitions[0].partitionType;
|
|
||||||
|
|
||||||
// Find the next partition (if there is one) and recurse....
|
|
||||||
if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 0) &&
|
|
||||||
(partNum < (NUM_LOGICALS - 1))) {
|
|
||||||
partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
|
|
||||||
partNum + 1);
|
|
||||||
} else {
|
|
||||||
partNum++;
|
|
||||||
} // if another partition
|
|
||||||
} // Not enough space for all the logicals (or previous error encountered)
|
|
||||||
return (partNum);
|
|
||||||
} // MBRData::ReadLogicalPart()
|
|
||||||
|
|
||||||
// Show the MBR data to the user....
|
// Show the MBR data to the user....
|
||||||
void MBRData::DisplayMBRData(void) {
|
void MBRData::DisplayMBRData(void) {
|
||||||
@@ -373,10 +318,10 @@ void MBRData::DisplayMBRData(void) {
|
|||||||
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
|
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
|
||||||
printf("MBR partitions:\n");
|
printf("MBR partitions:\n");
|
||||||
printf("Number\t Boot\t Start (sector)\t Length (sectors)\tType\n");
|
printf("Number\t Boot\t Start (sector)\t Length (sectors)\tType\n");
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < MAX_MBR_PARTS; i++) {
|
||||||
if (partitions[i].lengthLBA != 0) {
|
if (partitions[i].lengthLBA != 0) {
|
||||||
if (partitions[i].status && 0x80) // it's bootable
|
if (partitions[i].status && 0x80) // it's bootable
|
||||||
bootCode = '*';
|
bootCode = '*';
|
||||||
else
|
else
|
||||||
bootCode = ' ';
|
bootCode = ' ';
|
||||||
printf("%4d\t %c\t%13lu\t%15lu \t0x%02X\n", i + 1, bootCode,
|
printf("%4d\t %c\t%13lu\t%15lu \t0x%02X\n", i + 1, bootCode,
|
||||||
@@ -384,31 +329,144 @@ void MBRData::DisplayMBRData(void) {
|
|||||||
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
|
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
|
printf("\nDisk size is %llu sectors (%s)\n", (unsigned long long) diskSize,
|
||||||
// Now display logical partition data....
|
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
|
||||||
if (logicals[i].lengthLBA != 0) {
|
|
||||||
printf("%4d\t%13lu\t%15lu \t0x%02X\n", i + 5, (unsigned long) logicals[i].firstLBA,
|
|
||||||
(unsigned long) logicals[i].lengthLBA, logicals[i].partitionType);
|
|
||||||
} // if
|
|
||||||
} // for
|
|
||||||
printf("\nDisk size is %lu sectors (%s)\n", (unsigned long) diskSize,
|
|
||||||
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
|
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
|
||||||
} // MBRData::DisplayMBRData()
|
} // MBRData::DisplayMBRData()
|
||||||
|
|
||||||
|
// Displays the state, as a word, on stdout. Used for debugging & to
|
||||||
|
// tell the user about the MBR state when the program launches....
|
||||||
|
void MBRData::ShowState(void) {
|
||||||
|
switch (state) {
|
||||||
|
case invalid:
|
||||||
|
printf(" MBR: not present\n");
|
||||||
|
break;
|
||||||
|
case gpt:
|
||||||
|
printf(" MBR: protective\n");
|
||||||
|
break;
|
||||||
|
case hybrid:
|
||||||
|
printf(" MBR: hybrid\n");
|
||||||
|
break;
|
||||||
|
case mbr:
|
||||||
|
printf(" MBR: MBR only\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("\a MBR: unknown -- bug!\n");
|
||||||
|
break;
|
||||||
|
} // switch
|
||||||
|
} // MBRData::ShowState()
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* *
|
||||||
|
* Functions that set or get disk metadata (CHS geometry, disk size, *
|
||||||
|
* etc.) *
|
||||||
|
* *
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
// Sets the CHS geometry. CHS geometry is used by LBAtoCHS() function.
|
||||||
|
// Note that this only sets the heads and sectors; the number of
|
||||||
|
// cylinders is determined by these values and the disk size.
|
||||||
|
void MBRData::SetCHSGeom(uint32_t h, uint32_t s) {
|
||||||
|
if ((h <= MAX_HEADS) && (s <= MAX_SECSPERTRACK)) {
|
||||||
|
numHeads = h;
|
||||||
|
numSecspTrack = s;
|
||||||
|
} else {
|
||||||
|
printf("Warning! Attempt to set invalid CHS geometry!\n");
|
||||||
|
} // if/else
|
||||||
|
} // MBRData::SetCHSGeom()
|
||||||
|
|
||||||
|
// Converts 64-bit LBA value to MBR-style CHS value. Returns 1 if conversion
|
||||||
|
// was within the range that can be expressed by CHS (including 0, for an
|
||||||
|
// empty partition), 0 if the value is outside that range, and -1 if chs is
|
||||||
|
// invalid.
|
||||||
|
int MBRData::LBAtoCHS(uint64_t lba, uint8_t * chs) {
|
||||||
|
uint64_t cylinder, head, sector; // all numbered from 0
|
||||||
|
uint64_t remainder;
|
||||||
|
int retval = 1;
|
||||||
|
int done = 0;
|
||||||
|
|
||||||
|
if (chs != NULL) {
|
||||||
|
// Special case: In case of 0 LBA value, zero out CHS values....
|
||||||
|
if (lba == 0) {
|
||||||
|
chs[0] = chs[1] = chs[2] = UINT8_C(0);
|
||||||
|
done = 1;
|
||||||
|
} // if
|
||||||
|
// If LBA value is too large for CHS, max out CHS values....
|
||||||
|
if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
|
||||||
|
chs[0] = 254;
|
||||||
|
chs[1] = chs[2] = 255;
|
||||||
|
done = 1;
|
||||||
|
retval = 0;
|
||||||
|
} // if
|
||||||
|
// If neither of the above applies, compute CHS values....
|
||||||
|
if (!done) {
|
||||||
|
cylinder = lba / (uint64_t) (numHeads * numSecspTrack);
|
||||||
|
remainder = lba - (cylinder * numHeads * numSecspTrack);
|
||||||
|
head = remainder / numSecspTrack;
|
||||||
|
remainder -= head * numSecspTrack;
|
||||||
|
sector = remainder;
|
||||||
|
if (head < numHeads)
|
||||||
|
chs[0] = head;
|
||||||
|
else
|
||||||
|
retval = 0;
|
||||||
|
if (sector < numSecspTrack) {
|
||||||
|
chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
|
||||||
|
chs[2] = (uint8_t) (cylinder & UINT64_C(0xFF));
|
||||||
|
} else {
|
||||||
|
retval = 0;
|
||||||
|
} // if/else
|
||||||
|
} // if value is expressible and non-0
|
||||||
|
} else { // Invalid (NULL) chs pointer
|
||||||
|
retval = -1;
|
||||||
|
} // if CHS pointer valid
|
||||||
|
return (retval);
|
||||||
|
} // MBRData::LBAtoCHS()
|
||||||
|
|
||||||
|
/*****************************************************
|
||||||
|
* *
|
||||||
|
* Functions to create, delete, or change partitions *
|
||||||
|
* *
|
||||||
|
*****************************************************/
|
||||||
|
|
||||||
|
// Empty all data. Meant mainly for calling by constructors, but it's also
|
||||||
|
// used by the hybrid MBR functions in the GPTData class.
|
||||||
|
void MBRData::EmptyMBR(int clearBootloader) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Zero out the boot loader section, the disk signature, and the
|
||||||
|
// 2-byte nulls area only if requested to do so. (This is the
|
||||||
|
// default.)
|
||||||
|
if (clearBootloader == 1) {
|
||||||
|
for (i = 0; i < 440; i++)
|
||||||
|
code[i] = 0;
|
||||||
|
diskSignature = (uint32_t) rand();
|
||||||
|
nulls = 0;
|
||||||
|
} // if
|
||||||
|
|
||||||
|
// Blank out the partitions
|
||||||
|
for (i = 0; i < MAX_MBR_PARTS; i++) {
|
||||||
|
partitions[i].status = UINT8_C(0);
|
||||||
|
partitions[i].firstSector[0] = UINT8_C(0);
|
||||||
|
partitions[i].firstSector[1] = UINT8_C(0);
|
||||||
|
partitions[i].firstSector[2] = UINT8_C(0);
|
||||||
|
partitions[i].partitionType = UINT8_C(0);
|
||||||
|
partitions[i].lastSector[0] = UINT8_C(0);
|
||||||
|
partitions[i].lastSector[1] = UINT8_C(0);
|
||||||
|
partitions[i].lastSector[2] = UINT8_C(0);
|
||||||
|
partitions[i].firstLBA = UINT32_C(0);
|
||||||
|
partitions[i].lengthLBA = UINT32_C(0);
|
||||||
|
} // for
|
||||||
|
MBRSignature = MBR_SIGNATURE;
|
||||||
|
} // MBRData::EmptyMBR()
|
||||||
|
|
||||||
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
|
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
|
||||||
void MBRData::MakeProtectiveMBR(int clearBoot) {
|
void MBRData::MakeProtectiveMBR(int clearBoot) {
|
||||||
int i;
|
|
||||||
|
EmptyMBR(clearBoot);
|
||||||
|
|
||||||
// Initialize variables
|
// Initialize variables
|
||||||
nulls = 0;
|
nulls = 0;
|
||||||
MBRSignature = MBR_SIGNATURE;
|
MBRSignature = MBR_SIGNATURE;
|
||||||
|
|
||||||
if (clearBoot > 0) {
|
|
||||||
for (i = 0; i < 440; i++)
|
|
||||||
code[i] = (uint8_t) 0;
|
|
||||||
} // if
|
|
||||||
|
|
||||||
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
|
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
|
||||||
|
|
||||||
// Write CHS data. This maxes out the use of the disk, as much as
|
// Write CHS data. This maxes out the use of the disk, as much as
|
||||||
@@ -427,44 +485,43 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
|
|||||||
partitions[0].partitionType = UINT8_C(0xEE);
|
partitions[0].partitionType = UINT8_C(0xEE);
|
||||||
partitions[0].firstLBA = UINT32_C(1);
|
partitions[0].firstLBA = UINT32_C(1);
|
||||||
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
|
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
|
||||||
partitions[0].lengthLBA = diskSize - 1;
|
partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1);
|
||||||
} else { // disk is too big to represent, so fake it...
|
} else { // disk is too big to represent, so fake it...
|
||||||
partitions[0].lengthLBA = UINT32_MAX;
|
partitions[0].lengthLBA = UINT32_MAX;
|
||||||
} // if/else
|
} // if/else
|
||||||
|
|
||||||
// Zero out three unused primary partitions...
|
|
||||||
for (i = 1; i < 4; i++) {
|
|
||||||
partitions[i].status = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].partitionType = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].firstLBA = UINT32_C(0);
|
|
||||||
partitions[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
// Zero out all the logical partitions. Not necessary for data
|
|
||||||
// integrity on write, but eliminates stray entries if user wants
|
|
||||||
// to view the MBR after converting the disk
|
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
|
||||||
logicals[i].status = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].partitionType = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].firstLBA = UINT32_C(0);
|
|
||||||
logicals[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
state = gpt;
|
state = gpt;
|
||||||
} // MBRData::MakeProtectiveMBR()
|
} // MBRData::MakeProtectiveMBR()
|
||||||
|
|
||||||
|
// Create a partition of the specified number, starting LBA, and
|
||||||
|
// length. This function does *NO* error checking, so it's possible
|
||||||
|
// to seriously screw up a partition table using this function!
|
||||||
|
// Note: This function should NOT be used to create the 0xEE partition
|
||||||
|
// in a conventional GPT configuration, since that partition has
|
||||||
|
// specific size requirements that this function won't handle. It may
|
||||||
|
// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
|
||||||
|
// since those toss the rulebook away anyhow....
|
||||||
|
void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
|
||||||
|
int bootable) {
|
||||||
|
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
|
||||||
|
partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
|
||||||
|
partitions[num].firstSector[0] = UINT8_C(0);
|
||||||
|
partitions[num].firstSector[1] = UINT8_C(0);
|
||||||
|
partitions[num].firstSector[2] = UINT8_C(0);
|
||||||
|
partitions[num].partitionType = (uint8_t) type;
|
||||||
|
partitions[num].lastSector[0] = UINT8_C(0);
|
||||||
|
partitions[num].lastSector[1] = UINT8_C(0);
|
||||||
|
partitions[num].lastSector[2] = UINT8_C(0);
|
||||||
|
partitions[num].firstLBA = start;
|
||||||
|
partitions[num].lengthLBA = length;
|
||||||
|
// If this is a "real" partition, set its CHS geometry
|
||||||
|
if (length > 0) {
|
||||||
|
LBAtoCHS((uint64_t) start, partitions[num].firstSector);
|
||||||
|
LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector);
|
||||||
|
} // if (length > 0)
|
||||||
|
} // if valid partition number
|
||||||
|
} // MBRData::MakePart()
|
||||||
|
|
||||||
// Create a partition that fills the most available space. Returns
|
// Create a partition that fills the most available space. Returns
|
||||||
// 1 if partition was created, 0 otherwise. Intended for use in
|
// 1 if partition was created, 0 otherwise. Intended for use in
|
||||||
// creating hybrid MBRs.
|
// creating hybrid MBRs.
|
||||||
@@ -482,11 +539,11 @@ int MBRData::MakeBiggestPart(int i, int type) {
|
|||||||
if (firstBlock != UINT32_C(0)) { // something's free...
|
if (firstBlock != UINT32_C(0)) { // something's free...
|
||||||
lastBlock = FindLastInFree(firstBlock);
|
lastBlock = FindLastInFree(firstBlock);
|
||||||
segmentSize = lastBlock - firstBlock + UINT32_C(1);
|
segmentSize = lastBlock - firstBlock + UINT32_C(1);
|
||||||
if (segmentSize > selectedSize) {
|
if (segmentSize > selectedSize) {
|
||||||
selectedSize = segmentSize;
|
selectedSize = segmentSize;
|
||||||
selectedSegment = firstBlock;
|
selectedSegment = firstBlock;
|
||||||
} // if
|
} // if
|
||||||
start = lastBlock + 1;
|
start = lastBlock + 1;
|
||||||
} // if
|
} // if
|
||||||
} while (firstBlock != 0);
|
} while (firstBlock != 0);
|
||||||
if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
|
if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
|
||||||
@@ -517,18 +574,19 @@ void MBRData::DeletePartition(int i) {
|
|||||||
// Used to help keep GPT & hybrid MBR partitions in sync....
|
// Used to help keep GPT & hybrid MBR partitions in sync....
|
||||||
int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
|
int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
|
||||||
uint32_t start32, length32;
|
uint32_t start32, length32;
|
||||||
int i, j, deleted = 0;
|
int i, deleted = 0;
|
||||||
|
|
||||||
if ((state == hybrid) && (start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
|
if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
|
||||||
start32 = (uint32_t) start64;
|
start32 = (uint32_t) start64;
|
||||||
length32 = (uint32_t) length64;
|
length32 = (uint32_t) length64;
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < MAX_MBR_PARTS; i++) {
|
||||||
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
|
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
|
||||||
(partitions[i].partitionType != 0xEE)) {
|
(partitions[i].partitionType != 0xEE)) {
|
||||||
DeletePartition(i);
|
DeletePartition(i);
|
||||||
OptimizeEESize();
|
if (state == hybrid)
|
||||||
|
OptimizeEESize();
|
||||||
deleted = 1;
|
deleted = 1;
|
||||||
} // if (match found)
|
} // if (match found)
|
||||||
} // for i (partition scan)
|
} // for i (partition scan)
|
||||||
} // if (hybrid & GPT partition < 2TiB)
|
} // if (hybrid & GPT partition < 2TiB)
|
||||||
return deleted;
|
return deleted;
|
||||||
@@ -554,74 +612,24 @@ void MBRData::OptimizeEESize(void) {
|
|||||||
partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
|
partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
|
||||||
} // if free space after
|
} // if free space after
|
||||||
} // if partition is 0xEE
|
} // if partition is 0xEE
|
||||||
if (typeFlag == 0) { // No non-hybrid partitions found
|
|
||||||
MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
|
|
||||||
} // if
|
|
||||||
} // for partition loop
|
} // for partition loop
|
||||||
|
if (typeFlag == 0) { // No non-hybrid partitions found
|
||||||
|
MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
|
||||||
|
} // if
|
||||||
} // MBRData::OptimizeEESize()
|
} // MBRData::OptimizeEESize()
|
||||||
|
|
||||||
// Return a pointer to a primary or logical partition, or NULL if
|
/****************************************
|
||||||
// the partition is out of range....
|
* *
|
||||||
struct MBRRecord* MBRData::GetPartition(int i) {
|
* Functions to find data on free space *
|
||||||
MBRRecord* thePart = NULL;
|
* *
|
||||||
|
****************************************/
|
||||||
if ((i >= 0) && (i < 4)) { // primary partition
|
|
||||||
thePart = &partitions[i];
|
|
||||||
} // if
|
|
||||||
if ((i >= 4) && (i < (NUM_LOGICALS + 4))) {
|
|
||||||
thePart = &logicals[i - 4];
|
|
||||||
} // if
|
|
||||||
return thePart;
|
|
||||||
} // GetPartition()
|
|
||||||
|
|
||||||
// Displays the state, as a word, on stdout. Used for debugging & to
|
|
||||||
// tell the user about the MBR state when the program launches....
|
|
||||||
void MBRData::ShowState(void) {
|
|
||||||
switch (state) {
|
|
||||||
case invalid:
|
|
||||||
printf(" MBR: not present\n");
|
|
||||||
break;
|
|
||||||
case gpt:
|
|
||||||
printf(" MBR: protective\n");
|
|
||||||
break;
|
|
||||||
case hybrid:
|
|
||||||
printf(" MBR: hybrid\n");
|
|
||||||
break;
|
|
||||||
case mbr:
|
|
||||||
printf(" MBR: MBR only\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("\a MBR: unknown -- bug!\n");
|
|
||||||
break;
|
|
||||||
} // switch
|
|
||||||
} // MBRData::ShowState()
|
|
||||||
|
|
||||||
// Create a primary partition of the specified number, starting LBA,
|
|
||||||
// and length. This function does *NO* error checking, so it's possible
|
|
||||||
// to seriously screw up a partition table using this function! It's
|
|
||||||
// intended as a way to create a hybrid MBR, which is a pretty funky
|
|
||||||
// setup to begin with....
|
|
||||||
void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
|
|
||||||
int bootable) {
|
|
||||||
|
|
||||||
partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
|
|
||||||
partitions[num].firstSector[0] = UINT8_C(0);
|
|
||||||
partitions[num].firstSector[1] = UINT8_C(0);
|
|
||||||
partitions[num].firstSector[2] = UINT8_C(0);
|
|
||||||
partitions[num].partitionType = (uint8_t) type;
|
|
||||||
partitions[num].lastSector[0] = UINT8_C(0);
|
|
||||||
partitions[num].lastSector[1] = UINT8_C(0);
|
|
||||||
partitions[num].lastSector[2] = UINT8_C(0);
|
|
||||||
partitions[num].firstLBA = start;
|
|
||||||
partitions[num].lengthLBA = length;
|
|
||||||
} // MakePart()
|
|
||||||
|
|
||||||
// Finds the first free space on the disk from start onward; returns 0
|
// Finds the first free space on the disk from start onward; returns 0
|
||||||
// if none available....
|
// if none available....
|
||||||
uint32_t MBRData::FindFirstAvailable(uint32_t start) {
|
uint32_t MBRData::FindFirstAvailable(uint32_t start) {
|
||||||
uint32_t first;
|
uint32_t first;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int firstMoved = 0;
|
int firstMoved;
|
||||||
|
|
||||||
first = start;
|
first = start;
|
||||||
|
|
||||||
@@ -638,7 +646,7 @@ uint32_t MBRData::FindFirstAvailable(uint32_t start) {
|
|||||||
(first < (partitions[i].firstLBA + partitions[i].lengthLBA))) {
|
(first < (partitions[i].firstLBA + partitions[i].lengthLBA))) {
|
||||||
first = partitions[i].firstLBA + partitions[i].lengthLBA;
|
first = partitions[i].firstLBA + partitions[i].lengthLBA;
|
||||||
firstMoved = 1;
|
firstMoved = 1;
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
} while (firstMoved == 1);
|
} while (firstMoved == 1);
|
||||||
if (first >= diskSize)
|
if (first >= diskSize)
|
||||||
@@ -651,7 +659,7 @@ uint32_t MBRData::FindLastInFree(uint32_t start) {
|
|||||||
uint32_t nearestStart;
|
uint32_t nearestStart;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
if (diskSize <= UINT32_MAX)
|
if ((diskSize <= UINT32_MAX) && (diskSize > 0))
|
||||||
nearestStart = diskSize - 1;
|
nearestStart = diskSize - 1;
|
||||||
else
|
else
|
||||||
nearestStart = UINT32_MAX - 1;
|
nearestStart = UINT32_MAX - 1;
|
||||||
@@ -688,6 +696,8 @@ int MBRData::IsFree(uint32_t sector) {
|
|||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
first = partitions[i].firstLBA;
|
first = partitions[i].firstLBA;
|
||||||
|
// Note: Weird two-line thing to avoid subtracting 1 from a 0 value
|
||||||
|
// for an unsigned int....
|
||||||
last = first + partitions[i].lengthLBA;
|
last = first + partitions[i].lengthLBA;
|
||||||
if (last > 0) last--;
|
if (last > 0) last--;
|
||||||
if ((first <= sector) && (last >= sector))
|
if ((first <= sector) && (last >= sector))
|
||||||
@@ -696,6 +706,12 @@ int MBRData::IsFree(uint32_t sector) {
|
|||||||
return isFree;
|
return isFree;
|
||||||
} // MBRData::IsFree()
|
} // MBRData::IsFree()
|
||||||
|
|
||||||
|
/******************************************************
|
||||||
|
* *
|
||||||
|
* Functions that extract data on specific partitions *
|
||||||
|
* *
|
||||||
|
******************************************************/
|
||||||
|
|
||||||
uint8_t MBRData::GetStatus(int i) {
|
uint8_t MBRData::GetStatus(int i) {
|
||||||
MBRRecord* thePart;
|
MBRRecord* thePart;
|
||||||
uint8_t retval;
|
uint8_t retval;
|
||||||
@@ -729,7 +745,7 @@ uint32_t MBRData::GetFirstSector(int i) {
|
|||||||
retval = thePart->firstLBA;
|
retval = thePart->firstLBA;
|
||||||
} else
|
} else
|
||||||
retval = UINT32_C(0);
|
retval = UINT32_C(0);
|
||||||
return retval;
|
return retval;
|
||||||
} // MBRData::GetFirstSector()
|
} // MBRData::GetFirstSector()
|
||||||
|
|
||||||
uint32_t MBRData::GetLength(int i) {
|
uint32_t MBRData::GetLength(int i) {
|
||||||
@@ -741,7 +757,7 @@ uint32_t MBRData::GetLength(int i) {
|
|||||||
retval = thePart->lengthLBA;
|
retval = thePart->lengthLBA;
|
||||||
} else
|
} else
|
||||||
retval = UINT32_C(0);
|
retval = UINT32_C(0);
|
||||||
return retval;
|
return retval;
|
||||||
} // MBRData::GetLength()
|
} // MBRData::GetLength()
|
||||||
|
|
||||||
// Return the MBR data as a GPT partition....
|
// Return the MBR data as a GPT partition....
|
||||||
@@ -772,7 +788,23 @@ GPTPart MBRData::AsGPT(int i) {
|
|||||||
newPart.SetUniqueGUID(1);
|
newPart.SetUniqueGUID(1);
|
||||||
newPart.SetAttributes(0);
|
newPart.SetAttributes(0);
|
||||||
newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
|
newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
|
||||||
} // if
|
} // if not extended, protective, or non-existent
|
||||||
} // if
|
} // if (origPart != NULL)
|
||||||
return newPart;
|
return newPart;
|
||||||
} // MBRData::AsGPT()
|
} // MBRData::AsGPT()
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* *
|
||||||
|
* Protected functions *
|
||||||
|
* *
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
// Return a pointer to a primary or logical partition, or NULL if
|
||||||
|
// the partition is out of range....
|
||||||
|
struct MBRRecord* MBRData::GetPartition(int i) {
|
||||||
|
MBRRecord* thePart = NULL;
|
||||||
|
|
||||||
|
if ((i >= 0) && (i < MAX_MBR_PARTS))
|
||||||
|
thePart = &partitions[i];
|
||||||
|
return thePart;
|
||||||
|
} // GetPartition()
|
||||||
|
|||||||
62
mbr.h
62
mbr.h
@@ -12,9 +12,12 @@
|
|||||||
#define __MBRSTRUCTS
|
#define __MBRSTRUCTS
|
||||||
|
|
||||||
#define MBR_SIGNATURE UINT16_C(0xAA55)
|
#define MBR_SIGNATURE UINT16_C(0xAA55)
|
||||||
|
#define MAX_HEADS 255 /* numbered 0 - 254 */
|
||||||
|
#define MAX_SECSPERTRACK 63 /* numbered 1 - 63 */
|
||||||
|
#define MAX_CYLINDERS 1024 /* numbered 0 - 1023 */
|
||||||
|
|
||||||
// Maximum number of logical partitions supported
|
// Maximum number of MBR partitions
|
||||||
#define NUM_LOGICALS 124
|
#define MAX_MBR_PARTS 128
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -36,9 +39,10 @@ struct MBRRecord {
|
|||||||
uint32_t lengthLBA;
|
uint32_t lengthLBA;
|
||||||
}; // struct MBRRecord
|
}; // struct MBRRecord
|
||||||
|
|
||||||
// Create a 512-byte data structure into which the MBR can be loaded in one
|
// A 512-byte data structure into which the MBR can be loaded in one
|
||||||
// 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.
|
||||||
struct TempMBR {
|
struct TempMBR {
|
||||||
uint8_t code[440];
|
uint8_t code[440];
|
||||||
uint32_t diskSignature;
|
uint32_t diskSignature;
|
||||||
@@ -47,20 +51,6 @@ struct TempMBR {
|
|||||||
uint16_t MBRSignature;
|
uint16_t MBRSignature;
|
||||||
}; // struct TempMBR
|
}; // struct TempMBR
|
||||||
|
|
||||||
// Extended Boot Record (EBR) data, used to hold one logical partition's
|
|
||||||
// data within an extended partition. Includes pointer to next record for
|
|
||||||
// in-memory linked-list access. This is similar to MBRData, but with a
|
|
||||||
// few tweaks....
|
|
||||||
struct EBRRecord {
|
|
||||||
uint8_t code[446]; // generally 0s (and we don't care if they aren't)
|
|
||||||
// First partition entry defines partition; second points to next
|
|
||||||
// entry in on-disk linked list; remaining two are unused. Note that
|
|
||||||
// addresses are relative to the extended partition, not to the disk
|
|
||||||
// as a whole.
|
|
||||||
struct MBRRecord partitions[4];
|
|
||||||
uint16_t MBRSignature;
|
|
||||||
}; // struct EBRRecord
|
|
||||||
|
|
||||||
// Possible states of the MBR
|
// Possible states of the MBR
|
||||||
enum MBRValidity {invalid, gpt, hybrid, mbr};
|
enum MBRValidity {invalid, gpt, hybrid, mbr};
|
||||||
|
|
||||||
@@ -70,45 +60,55 @@ protected:
|
|||||||
uint8_t code[440];
|
uint8_t code[440];
|
||||||
uint32_t diskSignature;
|
uint32_t diskSignature;
|
||||||
uint16_t nulls;
|
uint16_t nulls;
|
||||||
struct MBRRecord partitions[4];
|
// MAX_MBR_PARTS defaults to 128. This array holds both the primary and
|
||||||
|
// the logical partitions, to simplify data retrieval for GPT conversions.
|
||||||
|
struct MBRRecord partitions[MAX_MBR_PARTS];
|
||||||
uint16_t MBRSignature;
|
uint16_t MBRSignature;
|
||||||
|
|
||||||
// Above are basic MBR data; now add more stuff....
|
// Above are basic MBR data; now add more stuff....
|
||||||
uint32_t blockSize; // block size (usually 512)
|
uint32_t blockSize; // block size (usually 512)
|
||||||
uint64_t diskSize; // size in blocks
|
uint64_t diskSize; // size in blocks
|
||||||
|
uint64_t numHeads; // number of heads, in CHS scheme
|
||||||
|
uint64_t numSecspTrack; // number of sectors per track, in CHS scheme
|
||||||
char device[256];
|
char device[256];
|
||||||
// Now an array of partitions for the logicals, in array form (easier
|
|
||||||
// than a linked list, and good enough for the GPT itself, so....)
|
|
||||||
struct MBRRecord logicals[NUM_LOGICALS];
|
|
||||||
MBRValidity state;
|
MBRValidity state;
|
||||||
struct MBRRecord* GetPartition(int i); // Return primary or logical partition
|
struct MBRRecord* GetPartition(int i); // Return primary or logical partition
|
||||||
public:
|
public:
|
||||||
MBRData(void);
|
MBRData(void);
|
||||||
MBRData(char* deviceFilename);
|
MBRData(char* deviceFilename);
|
||||||
~MBRData(void);
|
~MBRData(void);
|
||||||
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
|
|
||||||
void EmptyMBR(int clearBootloader = 1);
|
// File I/O functions...
|
||||||
void SetDiskSize(uint64_t ds) {diskSize = ds;}
|
|
||||||
int ReadMBRData(char* deviceFilename);
|
int ReadMBRData(char* deviceFilename);
|
||||||
void ReadMBRData(int fd, int checkBlockSize = 1);
|
void ReadMBRData(int fd, int checkBlockSize = 1);
|
||||||
|
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
||||||
|
int partNum);
|
||||||
int WriteMBRData(void);
|
int WriteMBRData(void);
|
||||||
void WriteMBRData(int fd);
|
void WriteMBRData(int fd);
|
||||||
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
||||||
// or -1 if there was a problem....
|
// or -1 if there was a problem....
|
||||||
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
|
||||||
int partNum);
|
// Display data for user...
|
||||||
void DisplayMBRData(void);
|
void DisplayMBRData(void);
|
||||||
void MakeProtectiveMBR(int clearBoot = 0);
|
|
||||||
MBRValidity GetValidity(void) {return state;}
|
|
||||||
void ShowValidity(void);
|
|
||||||
void ShowState(void);
|
void ShowState(void);
|
||||||
|
|
||||||
|
// Functions that set or get disk metadata (size, CHS geometry, etc.)
|
||||||
|
void SetDiskSize(uint64_t ds) {diskSize = ds;}
|
||||||
|
MBRValidity GetValidity(void) {return state;}
|
||||||
|
void SetHybrid(void) {state = hybrid;} // Set hybrid flag
|
||||||
|
void SetCHSGeom(uint32_t h, uint32_t s);
|
||||||
|
int LBAtoCHS(uint64_t lba, uint8_t * chs); // Convert LBA to CHS
|
||||||
|
|
||||||
|
// Functions to create, delete, or change partitions
|
||||||
|
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
|
||||||
|
void EmptyMBR(int clearBootloader = 1);
|
||||||
|
void MakeProtectiveMBR(int clearBoot = 0);
|
||||||
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
|
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
|
||||||
int bootable = 0);
|
int bootable = 0);
|
||||||
int MakeBiggestPart(int i, int type); // Make partition filling most space
|
int MakeBiggestPart(int i, int type); // Make partition filling most space
|
||||||
void DeletePartition(int i);
|
void DeletePartition(int i);
|
||||||
int DeleteByLocation(uint64_t start64, uint64_t length64);
|
int DeleteByLocation(uint64_t start64, uint64_t length64);
|
||||||
void OptimizeEESize(void);
|
void OptimizeEESize(void);
|
||||||
void SetHybrid(void) {state = hybrid;} // Set hybrid flag
|
|
||||||
|
|
||||||
// Functions to find information on free space....
|
// Functions to find information on free space....
|
||||||
uint32_t FindFirstAvailable(uint32_t start = 1);
|
uint32_t FindFirstAvailable(uint32_t start = 1);
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ PartTypes::PartTypes(void) {
|
|||||||
"EFI System"); // EFI System (parted marks Linux boot
|
"EFI System"); // EFI System (parted marks Linux boot
|
||||||
// partitions like this)
|
// partitions like this)
|
||||||
AddType(0xEF01, UINT64_C(0x11d333e7024dee41), UINT64_C(0x9FF381C70800699d),
|
AddType(0xEF01, UINT64_C(0x11d333e7024dee41), UINT64_C(0x9FF381C70800699d),
|
||||||
"MBR partition scheme"); // Whatever that is (from Wikipedia)
|
"MBR partition scheme"); // Used to nest an MBR table on a GPT disk
|
||||||
AddType(0xEF02, UINT64_C(0x6E6F644921686148), UINT64_C(0x4946456465654E74),
|
AddType(0xEF02, UINT64_C(0x6E6F644921686148), UINT64_C(0x4946456465654E74),
|
||||||
"BIOS boot partition"); //
|
"BIOS boot partition"); //
|
||||||
|
|
||||||
|
|||||||
22
support.cc
22
support.cc
@@ -205,7 +205,9 @@ int GetBlockSize(int fd) {
|
|||||||
result = SECTOR_SIZE;
|
result = SECTOR_SIZE;
|
||||||
// ENOTTY = inappropriate ioctl; probably being called on a disk image
|
// ENOTTY = inappropriate ioctl; probably being called on a disk image
|
||||||
// file, so don't display the warning message....
|
// file, so don't display the warning message....
|
||||||
if (errno != ENOTTY) {
|
// 32-bit code returns EINVAL, I don't know why. I know I'm treading on
|
||||||
|
// thin ice here, but it should be OK in all but very weird cases....
|
||||||
|
if ((errno != ENOTTY) && (errno != EINVAL)) {
|
||||||
printf("\aError %d when determining sector size! Setting sector size to %d\n",
|
printf("\aError %d when determining sector size! Setting sector size to %d\n",
|
||||||
errno, SECTOR_SIZE);
|
errno, SECTOR_SIZE);
|
||||||
} // if
|
} // if
|
||||||
@@ -434,8 +436,9 @@ void DiskSync(int fd) {
|
|||||||
uint64_t disksize(int fd, int *err) {
|
uint64_t disksize(int fd, int *err) {
|
||||||
long sz; // Do not delete; needed for Linux
|
long sz; // Do not delete; needed for Linux
|
||||||
long long b; // Do not delete; needed for Linux
|
long long b; // Do not delete; needed for Linux
|
||||||
uint64_t sectors = 0, bytes = 0; // size in sectors & bytes
|
uint64_t sectors = 0; // size in sectors
|
||||||
struct stat st;
|
off_t bytes = 0; // size in bytes
|
||||||
|
struct stat64 st;
|
||||||
|
|
||||||
// Note to self: I recall testing a simplified version of
|
// Note to self: I recall testing a simplified version of
|
||||||
// this code, similar to what's in the __APPLE__ block,
|
// this code, similar to what's in the __APPLE__ block,
|
||||||
@@ -462,17 +465,6 @@ uint64_t disksize(int fd, int *err) {
|
|||||||
sectors = (b >> 9);
|
sectors = (b >> 9);
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// if (*err) {
|
|
||||||
// sz = 0;
|
|
||||||
// if (errno != EFBIG)
|
|
||||||
// return sz;
|
|
||||||
// }
|
|
||||||
// *err = ioctl(fd, BLKGETSIZE64, &b);
|
|
||||||
// if (*err || b == 0 || b == sz)
|
|
||||||
// sectors = sz;
|
|
||||||
// else
|
|
||||||
// sectors = (b >> 9);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -480,7 +472,7 @@ uint64_t disksize(int fd, int *err) {
|
|||||||
// so let's assume it's a regular file (a QEMU image, dd backup, or
|
// so let's assume it's a regular file (a QEMU image, dd backup, or
|
||||||
// what have you) and see what stat() gives us....
|
// what have you) and see what stat() gives us....
|
||||||
if (sectors == 0) {
|
if (sectors == 0) {
|
||||||
if (fstat(fd, &st) == 0) {
|
if (fstat64(fd, &st) == 0) {
|
||||||
bytes = (uint64_t) st.st_size;
|
bytes = (uint64_t) st.st_size;
|
||||||
if ((bytes % UINT64_C(512)) != 0)
|
if ((bytes % UINT64_C(512)) != 0)
|
||||||
fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
|
fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
|
||||||
|
|||||||
14
support.h
14
support.h
@@ -4,6 +4,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef __GPTSUPPORT
|
||||||
|
#define __GPTSUPPORT
|
||||||
|
|
||||||
#if defined (__FreeBSD__) || defined (__APPLE__)
|
#if defined (__FreeBSD__) || defined (__APPLE__)
|
||||||
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
|
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
|
||||||
@@ -18,10 +22,10 @@
|
|||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#ifdef __FreeBSD__
|
||||||
|
#define fstat64 fstat
|
||||||
#ifndef __GPTSUPPORT
|
#define stat64 stat
|
||||||
#define __GPTSUPPORT
|
#endif
|
||||||
|
|
||||||
// Set this as a default
|
// Set this as a default
|
||||||
#define SECTOR_SIZE UINT32_C(512)
|
#define SECTOR_SIZE UINT32_C(512)
|
||||||
@@ -39,7 +43,7 @@
|
|||||||
// Number and size of GPT entries...
|
// Number and size of GPT entries...
|
||||||
#define NUM_GPT_ENTRIES 128
|
#define NUM_GPT_ENTRIES 128
|
||||||
#define GPT_SIZE 128
|
#define GPT_SIZE 128
|
||||||
#define HEADER_SIZE 92
|
#define HEADER_SIZE UINT32_C(92)
|
||||||
#define GPT_RESERVED 420
|
#define GPT_RESERVED 420
|
||||||
#define NAME_SIZE 72
|
#define NAME_SIZE 72
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user