Version 0.5.3 changes. Minor bug fixes & detection of the number of
logical sectors per physical sector on Linux 2.6.32 and above.
This commit is contained in:
17
CHANGELOG
17
CHANGELOG
@@ -1,3 +1,20 @@
|
||||
0.5.3 (1/??/2009):
|
||||
------------------
|
||||
|
||||
- Fixed bug in display of GUIDs when compiled with some versions of GCC.
|
||||
|
||||
- Eliminated warnings caused by additional checks in latest versions of
|
||||
GCC. These warnings were harmless, but to eliminate them I've added
|
||||
more error checking on disk I/O.
|
||||
|
||||
- Eliminated unnecessary warnings about potential data loss if the program
|
||||
was launched with the -l option or if writes aren't possible.
|
||||
|
||||
- Added code to set the partition boundary value based on the physical
|
||||
sector size. (FindAlignment() function.) This function, however, works
|
||||
only on Linux, and then only if the BLKPBSZGET ioctl is defined. This
|
||||
ioctl is new in kernel 2.6.32 or thereabouts.
|
||||
|
||||
0.5.2 (12/31/2009):
|
||||
-------------------
|
||||
|
||||
|
||||
27
README
27
README
@@ -53,23 +53,22 @@ to make it available.
|
||||
Caveats
|
||||
-------
|
||||
|
||||
THIS SOFTWARE IS EARLY BETA SOFTWARE! IF IT WIPES OUT YOUR HARD DISK OR
|
||||
EATS YOUR CAT, DON'T BLAME ME! To date, I've tested the software mainly on
|
||||
two USB flash drives, 2 GiB and 8 GiB in size. I've also made a few minor
|
||||
tweaks to a production system with a 500 GiB hard disk and made more
|
||||
extensive changes to a handful of 80-160 GiB hard disks. I believe all
|
||||
data-corruption bugs to be squashed, but I know full well that the odds of
|
||||
my missing something are high. This is particularly true for large drives;
|
||||
I have no way of testing the software with > 2TiB drives, which will test
|
||||
the 64-bit sector pointer support. I've received user reports of success
|
||||
with >2TiB drives, though.
|
||||
THIS SOFTWARE IS BETA SOFTWARE! IF IT WIPES OUT YOUR HARD DISK OR EATS YOUR
|
||||
CAT, DON'T BLAME ME! To date, I've tested the software on several USB flash
|
||||
drives, a handful of PATA and SATA hard disks, and several virtual disks in
|
||||
a QEMU environment. I believe all data-corruption bugs to be squashed, but
|
||||
I know full well that the odds of my missing something are high. This is
|
||||
particularly true for large drives; my only direct testing with such disks
|
||||
is with virtual QEMU disks. I've received user reports of success with
|
||||
RAID arrays over 2TiB in size, though.
|
||||
|
||||
My main development platform is a system running the 64-bit version of
|
||||
Ubuntu 8.04. I've also tested on 64-bit OpenSuSE, 32-bit Fedora 10, 32-bit
|
||||
Ubuntu 6.10, 64-bit Gentoo, 32-bit PowerPC Linux, 32-bit Intel-based Mac
|
||||
OS X, and 64-bit Fedora 7.1. Problems relating to 64-bit integers on the
|
||||
32-bit Linux have been common during development and may crop up in the
|
||||
future. The Mac OS X, FreeBSD, and big-endian (PowerPC) support are new.
|
||||
Fedora 11, 32-bit Ubuntu 6.10, 64-bit Ubunut 9.10, 64-bit Gentoo, 32-bit
|
||||
PowerPC Debian Linux, 32-bit Intel-based Mac OS X 10.5 and 10.6, and 64-bit
|
||||
FreeBSD 7.1. Problems relating to 64-bit integers on the 32-bit Linux have
|
||||
been common during development and may crop up in the future. The Mac OS X,
|
||||
FreeBSD, and big-endian (PowerPC) support are new.
|
||||
|
||||
Redistribution
|
||||
--------------
|
||||
|
||||
18
gdisk.8
18
gdisk.8
@@ -1,6 +1,6 @@
|
||||
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||
.\" May be distributed under the GNU General Public License
|
||||
.TH "GDISK" "8" "0.5.1" "Roderick W. Smith" "GPT fdisk Manual"
|
||||
.TH "GDISK" "8" "0.5.3" "Roderick W. Smith" "GPT fdisk Manual"
|
||||
.SH "NAME"
|
||||
gdisk \- GUID partition table (GPT) manipulator for Linux and Unix
|
||||
.SH "SYNOPSIS"
|
||||
@@ -420,9 +420,9 @@ not in \fBgdisk\fR) or sheer incredible coincidence.
|
||||
.B d
|
||||
Display the number of logical sectors per physical sector. This value
|
||||
determines the sector alignment that GPT fdisk enforces. See the
|
||||
description of the 'l' option for more details. Note that this value
|
||||
is not actually detected on a disk-by-disk basis; it's set to 8 as a
|
||||
blanket default.
|
||||
description of the 'l' option for more details. Note that this value is
|
||||
only auto-detected on Linux with a 2.6.32 kernel or later; on other
|
||||
platforms, it defaults to 8.
|
||||
|
||||
.TP
|
||||
.B e
|
||||
@@ -453,10 +453,10 @@ mid-physical-sector, though, performance can suffer on such drives, since
|
||||
important filesystem data structures can span physical sectors on the disk.
|
||||
To minimize such problems, GPT fdisk aligns the start of partitions on the
|
||||
boundary of presumed physical sectors. You can set the number of logical
|
||||
sectors per physical sector with this option. The default is 8, which is
|
||||
set blindly; GPT fdisk does not currently read this information from the
|
||||
disk. The default value will result in a tiny amount of wasted disk space
|
||||
on older disks with true 512-byte sectors but will otherwise be harmless.
|
||||
sectors per physical sector with this option. The default is 8, except on
|
||||
Linux 2.6.32 and later, in which case it's read from the disk. A value of 8
|
||||
will result in a tiny amount of wasted disk space on older disks with true
|
||||
512-byte sectors but will otherwise be harmless.
|
||||
|
||||
.TP
|
||||
.B m
|
||||
@@ -525,7 +525,7 @@ entering data. When only one option is possible, \fBgdisk\fR
|
||||
usually bypasses the prompt entirely.
|
||||
|
||||
.SH "BUGS"
|
||||
As of November 2009 (version 0.5.1), \fBgdisk\fR
|
||||
As of January 2010 (version 0.5.3), \fBgdisk\fR
|
||||
should be considered beta software. Known bugs and limitations include:
|
||||
|
||||
.TP
|
||||
|
||||
22
gdisk.cc
22
gdisk.cc
@@ -29,7 +29,7 @@ int main(int argc, char* argv[]) {
|
||||
int doMore = 1;
|
||||
char* device = NULL;
|
||||
|
||||
printf("GPT fdisk (gdisk) version 0.5.2\n\n");
|
||||
printf("GPT fdisk (gdisk) version 0.5.3\n\n");
|
||||
|
||||
if (argc == 2) { // basic usage
|
||||
if (SizesOK()) {
|
||||
@@ -48,6 +48,7 @@ int main(int argc, char* argv[]) {
|
||||
fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
|
||||
} // if/elseif/else
|
||||
if (device != NULL) {
|
||||
theGPT.JustLooking();
|
||||
doMore = theGPT.LoadPartitions(device);
|
||||
if (doMore) theGPT.DisplayGPTData();
|
||||
} // if
|
||||
@@ -61,19 +62,20 @@ int main(int argc, char* argv[]) {
|
||||
// wants to exit (such as after a 'w' or 'q' command).
|
||||
void MainMenu(char* filename, struct GPTData* theGPT) {
|
||||
char command, line[255], buFile[255];
|
||||
char* junk;
|
||||
int goOn = 1;
|
||||
PartTypes typeHelper;
|
||||
uint32_t temp1, temp2;
|
||||
|
||||
do {
|
||||
printf("\nCommand (? for help): ");
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
case 'b': case 'B':
|
||||
printf("Enter backup filename to save: ");
|
||||
fgets(line, 255, stdin);
|
||||
sscanf(line, "%s", &buFile);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%s", (char*) &buFile);
|
||||
theGPT->SaveGPTBackup(buFile);
|
||||
break;
|
||||
case 'c': case 'C':
|
||||
@@ -163,13 +165,14 @@ void ShowCommands(void) {
|
||||
// issues an exit command, such as 'w' or 'q'.
|
||||
void RecoveryMenu(char* filename, struct GPTData* theGPT) {
|
||||
char command, line[255], buFile[255];
|
||||
char* junk;
|
||||
PartTypes typeHelper;
|
||||
uint32_t temp1;
|
||||
int goOn = 1;
|
||||
|
||||
do {
|
||||
printf("\nrecovery/transformation command (? for help): ");
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
case 'b': case 'B':
|
||||
@@ -222,8 +225,8 @@ void RecoveryMenu(char* filename, struct GPTData* theGPT) {
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
printf("Enter backup filename to load: ");
|
||||
fgets(line, 255, stdin);
|
||||
sscanf(line, "%s", &buFile);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%s", (char*) &buFile);
|
||||
theGPT->LoadGPTBackup(buFile);
|
||||
break;
|
||||
case 'm': case 'M':
|
||||
@@ -286,6 +289,7 @@ void ShowRecoveryCommands(void) {
|
||||
// selects an exit command, such as 'w' or 'q'.
|
||||
void ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||
char command, line[255];
|
||||
char* junk;
|
||||
PartTypes typeHelper;
|
||||
uint32_t pn;
|
||||
uint32_t temp1, temp2;
|
||||
@@ -293,7 +297,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||
|
||||
do {
|
||||
printf("\nExpert command (? for help): ");
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
case 'a': case 'A':
|
||||
@@ -310,7 +314,7 @@ void ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||
} else printf("No partitions\n");
|
||||
break;
|
||||
case 'd': case 'D':
|
||||
printf("The number of logical sectors per physical sector is set to %d.\n",
|
||||
printf("The number of logical sectors per physical sector is %d.\n",
|
||||
theGPT->GetAlignment());
|
||||
break;
|
||||
case 'e': case 'E':
|
||||
|
||||
151
gpt.cc
151
gpt.cc
@@ -40,6 +40,7 @@ GPTData::GPTData(void) {
|
||||
partitions = NULL;
|
||||
state = gpt_valid;
|
||||
strcpy(device, "");
|
||||
justLooking = 0;
|
||||
mainCrcOk = 0;
|
||||
secondCrcOk = 0;
|
||||
mainPartsCrcOk = 0;
|
||||
@@ -58,6 +59,7 @@ GPTData::GPTData(char* filename) {
|
||||
partitions = NULL;
|
||||
state = gpt_invalid;
|
||||
strcpy(device, "");
|
||||
justLooking = 0;
|
||||
mainCrcOk = 0;
|
||||
secondCrcOk = 0;
|
||||
mainPartsCrcOk = 0;
|
||||
@@ -296,7 +298,7 @@ int GPTData::CheckHeaderValidity(void) {
|
||||
} else if ((mainHeader.revision != 0x00010000) && valid) {
|
||||
valid -= 1;
|
||||
printf("Unsupported GPT version in main header; read 0x%08lX, should be\n0x%08lX\n",
|
||||
(unsigned long) mainHeader.revision, UINT32_C(0x00010000));
|
||||
(unsigned long) mainHeader.revision, (unsigned long) UINT32_C(0x00010000));
|
||||
} // if/else/if
|
||||
|
||||
if (secondHeader.signature != GPT_SIGNATURE) {
|
||||
@@ -306,7 +308,7 @@ int GPTData::CheckHeaderValidity(void) {
|
||||
} else if ((secondHeader.revision != 0x00010000) && valid) {
|
||||
valid -= 2;
|
||||
printf("Unsupported GPT version in backup header; read 0x%08lX, should be\n0x%08lX\n",
|
||||
(unsigned long) mainHeader.revision, UINT32_C(0x00010000));
|
||||
(unsigned long) mainHeader.revision, (unsigned long) UINT32_C(0x00010000));
|
||||
} // if/else/if
|
||||
|
||||
// If MBR bad, check for an Apple disk signature
|
||||
@@ -515,7 +517,9 @@ void GPTData::PartitionScan(int fd) {
|
||||
if (apmFound) {
|
||||
printf("\n*******************************************************************\n");
|
||||
printf("This disk appears to contain an Apple-format (APM) partition table!\n");
|
||||
printf("It will be destroyed if you continue!\n");
|
||||
if (!justLooking) {
|
||||
printf("It will be destroyed if you continue!\n");
|
||||
} // if
|
||||
printf("*******************************************************************\n\n\a");
|
||||
} // if
|
||||
} // GPTData::PartitionScan()
|
||||
@@ -529,16 +533,19 @@ int GPTData::LoadPartitions(char* deviceFilename) {
|
||||
|
||||
// First, do a test to see if writing will be possible later....
|
||||
fd = OpenForWrite(deviceFilename);
|
||||
if (fd == -1)
|
||||
if ((fd == -1) && (!justLooking)) {
|
||||
printf("\aNOTE: Write test failed with error number %d. It will be "
|
||||
"impossible to save\nchanges to this disk's partition table!\n\n",
|
||||
errno);
|
||||
justLooking = 1;
|
||||
} // if
|
||||
close(fd);
|
||||
|
||||
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
|
||||
// store disk information....
|
||||
diskSize = disksize(fd, &err);
|
||||
blockSize = (uint32_t) GetBlockSize(fd);
|
||||
sectorAlignment = FindAlignment(fd);
|
||||
strcpy(device, deviceFilename);
|
||||
PartitionScan(fd); // Check for partition types & print summary
|
||||
|
||||
@@ -595,7 +602,9 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
|
||||
// Seek to and read the main GPT header
|
||||
lseek64(fd, 512, SEEK_SET);
|
||||
read(fd, &mainHeader, 512); // read main GPT header
|
||||
if (read(fd, &mainHeader, 512) != 512) { // read main GPT header
|
||||
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
|
||||
} // if
|
||||
mainCrcOk = CheckHeaderCRC(&mainHeader);
|
||||
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
|
||||
ReverseHeaderBytes(&mainHeader);
|
||||
@@ -620,7 +629,9 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
} // if/else (mainCrcOk)
|
||||
|
||||
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
|
||||
read(fd, &secondHeader, 512); // read secondary GPT header
|
||||
if (read(fd, &secondHeader, 512) != 512) { // read secondary GPT header
|
||||
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
|
||||
} // if
|
||||
secondCrcOk = CheckHeaderCRC(&secondHeader);
|
||||
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
|
||||
ReverseHeaderBytes(&secondHeader);
|
||||
@@ -628,7 +639,7 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
allOK = 0;
|
||||
state = gpt_invalid;
|
||||
fprintf(stderr, "Unable to seek to secondary GPT header at sector %llu!\n",
|
||||
diskSize - (UINT64_C(1)));
|
||||
(unsigned long long) (diskSize - (UINT64_C(1))));
|
||||
} // if/else lseek
|
||||
|
||||
// Return valid headers code: 0 = both headers bad; 1 = main header
|
||||
@@ -670,7 +681,9 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
if ((lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) && (secondCrcOk)) {
|
||||
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
|
||||
storage = (char*) malloc(sizeOfParts);
|
||||
read(fd, storage, sizeOfParts);
|
||||
if (read(fd, storage, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Error %d reading backup partition table!\n", errno);
|
||||
} // if
|
||||
newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
|
||||
free(storage);
|
||||
secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
|
||||
@@ -703,7 +716,9 @@ int GPTData::LoadMainTable(void) {
|
||||
// matches the stored value
|
||||
lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET);
|
||||
sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
|
||||
read(fd, partitions, sizeOfParts);
|
||||
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Error %d when loading the main partition table!\n", errno);
|
||||
} // if
|
||||
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
|
||||
mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
|
||||
if (IsLittleEndian() == 0)
|
||||
@@ -725,7 +740,9 @@ void GPTData::LoadSecondTableAsMain(void) {
|
||||
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
|
||||
SetGPTSize(secondHeader.numParts);
|
||||
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
|
||||
read(fd, partitions, sizeOfParts);
|
||||
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Read error %d! Misbehavior now likely!\n", errno);
|
||||
} // if
|
||||
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
|
||||
secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
|
||||
mainPartsCrcOk = secondPartsCrcOk;
|
||||
@@ -757,6 +774,13 @@ int GPTData::SaveGPTData(void) {
|
||||
} // if
|
||||
|
||||
// First do some final sanity checks....
|
||||
|
||||
// This test should only fail on read-only disks....
|
||||
if (justLooking) {
|
||||
printf("The justLooking flag is set. This probably means you can't write to the disk.\n");
|
||||
allOK = 0;
|
||||
} // if
|
||||
|
||||
// Is there enough space to hold the GPT headers and partition tables,
|
||||
// given the partition sizes?
|
||||
if (CheckGPTSize() > 0) {
|
||||
@@ -767,8 +791,8 @@ int GPTData::SaveGPTData(void) {
|
||||
if (mainHeader.backupLBA > diskSize) {
|
||||
fprintf(stderr, "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n"
|
||||
"problem (or it might not). Aborting!\n");
|
||||
printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n", diskSize,
|
||||
mainHeader.backupLBA);
|
||||
printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n",
|
||||
(unsigned long long) diskSize, (unsigned long long) mainHeader.backupLBA);
|
||||
allOK = 0;
|
||||
} // if
|
||||
// Check that second header is properly placed. Warn and ask if this should
|
||||
@@ -811,11 +835,10 @@ int GPTData::SaveGPTData(void) {
|
||||
printf("\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n");
|
||||
printf("MBR PARTITIONS!! THIS PROGRAM IS BETA QUALITY AT BEST. IF YOU LOSE ALL YOUR\n");
|
||||
printf("DATA, YOU HAVE ONLY YOURSELF TO BLAME IF YOU ANSWER 'Y' BELOW!\n\n");
|
||||
printf("Do you want to proceed, possibly destroying your data? (Y/N) ");
|
||||
fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &answer);
|
||||
if ((answer == 'Y') || (answer == 'y')) {
|
||||
printf("OK; writing new GPT partition table.\n");
|
||||
printf("Do you want to proceed, possibly destroying your data? ");
|
||||
answer = GetYN();
|
||||
if (answer == 'Y') {
|
||||
printf("OK; writing new GUID partition table (GPT).\n");
|
||||
} else {
|
||||
allOK = 0;
|
||||
} // if/else
|
||||
@@ -974,7 +997,9 @@ int GPTData::LoadGPTBackup(char* filename) {
|
||||
|
||||
// Load the main GPT header, check its vaility, and set the GPT
|
||||
// size based on the data
|
||||
read(fd, &mainHeader, 512);
|
||||
if (read(fd, &mainHeader, 512)) {
|
||||
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
|
||||
} // if
|
||||
mainCrcOk = CheckHeaderCRC(&mainHeader);
|
||||
|
||||
// Reverse byte order, if necessary
|
||||
@@ -984,7 +1009,9 @@ int GPTData::LoadGPTBackup(char* filename) {
|
||||
|
||||
// Load the backup GPT header in much the same way as the main
|
||||
// GPT header....
|
||||
read(fd, &secondHeader, 512);
|
||||
if (read(fd, &secondHeader, 512) != 512) {
|
||||
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
|
||||
} // if
|
||||
secondCrcOk = CheckHeaderCRC(&secondHeader);
|
||||
|
||||
// Reverse byte order, if necessary
|
||||
@@ -1018,7 +1045,9 @@ int GPTData::LoadGPTBackup(char* filename) {
|
||||
// Load main partition table, and record whether its CRC
|
||||
// matches the stored value
|
||||
sizeOfParts = numParts * sizeOfEntries;
|
||||
read(fd, partitions, sizeOfParts);
|
||||
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
|
||||
} // if
|
||||
|
||||
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
|
||||
mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
|
||||
@@ -1082,11 +1111,11 @@ void GPTData::DisplayGPTData(void) {
|
||||
(unsigned long long) diskSize, sizeInSI);
|
||||
printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr));
|
||||
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",
|
||||
(unsigned long) mainHeader.firstUsableLBA,
|
||||
(unsigned long) mainHeader.lastUsableLBA);
|
||||
printf("First usable sector is %llu, last usable sector is %llu\n",
|
||||
(unsigned long long) mainHeader.firstUsableLBA,
|
||||
(unsigned long long) mainHeader.lastUsableLBA);
|
||||
totalFree = FindFreeBlocks(&i, &temp);
|
||||
printf("Total free space is %llu sectors (%s)\n", totalFree,
|
||||
printf("Total free space is %llu sectors (%s)\n", (unsigned long long) totalFree,
|
||||
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
|
||||
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
|
||||
for (i = 0; i < mainHeader.numParts; i++) {
|
||||
@@ -1189,9 +1218,9 @@ void GPTData::CreatePartition(void) {
|
||||
} while (partitions[partNum].GetFirstLBA() != 0);
|
||||
|
||||
// Get first block for new partition...
|
||||
sprintf(prompt,
|
||||
"First sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
|
||||
firstBlock, lastBlock, firstInLargest);
|
||||
sprintf(prompt, "First sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
|
||||
(unsigned long long) firstBlock, (unsigned long long) lastBlock,
|
||||
(unsigned long long) firstInLargest);
|
||||
do {
|
||||
sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt);
|
||||
} while (IsFree(sector) == 0);
|
||||
@@ -1200,9 +1229,9 @@ void GPTData::CreatePartition(void) {
|
||||
|
||||
// Get last block for new partitions...
|
||||
lastBlock = FindLastInFree(firstBlock);
|
||||
sprintf(prompt,
|
||||
"Last sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
|
||||
firstBlock, lastBlock, lastBlock);
|
||||
sprintf(prompt, "Last sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
|
||||
(unsigned long long) firstBlock, (unsigned long long) lastBlock,
|
||||
(unsigned long long) lastBlock);
|
||||
do {
|
||||
sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt);
|
||||
} while (IsFree(sector) == 0);
|
||||
@@ -1273,7 +1302,7 @@ void GPTData::SetAttributes(uint32_t partNum) {
|
||||
// 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, sum;
|
||||
char blankSector[512], goOn = 'Y', blank = 'N';
|
||||
|
||||
for (i = 0; i < 512; i++) {
|
||||
@@ -1298,15 +1327,25 @@ int GPTData::DestroyGPT(int prompt) {
|
||||
#endif
|
||||
if (fd != -1) {
|
||||
lseek64(fd, mainHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
|
||||
write(fd, blankSector, 512); // blank it out
|
||||
if (write(fd, blankSector, 512) != 512) { // blank it out
|
||||
fprintf(stderr, "Warning! GPT main header not overwritten! Error is %d\n", errno);
|
||||
} // if
|
||||
lseek64(fd, mainHeader.partitionEntriesLBA * 512, SEEK_SET); // seek to partition table
|
||||
sum = 0;
|
||||
for (i = 0; i < GetBlocksInPartTable(); i++)
|
||||
write(fd, blankSector, 512);
|
||||
sum += write(fd, blankSector, 512);
|
||||
if (sum != 512 * GetBlocksInPartTable())
|
||||
fprintf(stderr, "Warning! GPT main partition table not overwritten! Error is %d\n", errno);
|
||||
lseek64(fd, secondHeader.partitionEntriesLBA * 512, SEEK_SET); // seek to partition table
|
||||
sum = 0;
|
||||
for (i = 0; i < GetBlocksInPartTable(); i++)
|
||||
write(fd, blankSector, 512);
|
||||
sum += write(fd, blankSector, 512);
|
||||
if (sum != 512 * GetBlocksInPartTable())
|
||||
fprintf(stderr, "Warning! GPT backup partition table not overwritten! Error is %d\n", errno);
|
||||
lseek64(fd, secondHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
|
||||
write(fd, blankSector, 512); // blank it out
|
||||
if (write(fd, blankSector, 512) != 512) { // blank it out
|
||||
fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
|
||||
} // if
|
||||
if (prompt) {
|
||||
printf("Blank out MBR? ");
|
||||
blank = GetYN();
|
||||
@@ -1318,7 +1357,9 @@ int GPTData::DestroyGPT(int prompt) {
|
||||
// structures).
|
||||
if (blank == 'Y') {
|
||||
lseek64(fd, 0, SEEK_SET);
|
||||
write(fd, blankSector, 512); // blank it out
|
||||
if (write(fd, blankSector, 512) != 512) { // blank it out
|
||||
fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
|
||||
} // if
|
||||
} else {
|
||||
printf("MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n"
|
||||
"with fdisk or another tool.\n");
|
||||
@@ -1352,21 +1393,26 @@ WhichToUse GPTData::UseWhichPartitions(void) {
|
||||
mbrState = protectiveMBR.GetValidity();
|
||||
|
||||
if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) {
|
||||
printf("\n\a***************************************************************\n"
|
||||
"Found invalid GPT and valid MBR; converting MBR to GPT format.\n"
|
||||
"THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n"
|
||||
"you don't want to convert your MBR partitions to GPT format!\n"
|
||||
"***************************************************************\n\n");
|
||||
printf("\n***************************************************************\n"
|
||||
"Found invalid GPT and valid MBR; converting MBR to GPT format.\n");
|
||||
if (!justLooking) {
|
||||
printf("\aTHIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n"
|
||||
"you don't want to convert your MBR partitions to GPT format!\n");
|
||||
} // if
|
||||
printf("***************************************************************\n\n");
|
||||
which = use_mbr;
|
||||
} // if
|
||||
|
||||
if ((state == gpt_invalid) && bsdFound) {
|
||||
printf("\n\a**********************************************************************\n"
|
||||
printf("\n**********************************************************************\n"
|
||||
"Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n"
|
||||
"to GPT format. THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n"
|
||||
"to GPT format.");
|
||||
if (!justLooking) {
|
||||
printf("\a THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n"
|
||||
"BSD partition will likely be unusable. Exit by typing 'q' if you don't\n"
|
||||
"want to convert your BSD partitions to GPT format!\n"
|
||||
"**********************************************************************\n\n");
|
||||
"want to convert your BSD partitions to GPT format!");
|
||||
} // if
|
||||
printf("\n**********************************************************************\n\n");
|
||||
which = use_bsd;
|
||||
} // if
|
||||
|
||||
@@ -1539,6 +1585,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
||||
int allOK = 1, typeCode, bootable;
|
||||
uint64_t length;
|
||||
char line[255];
|
||||
char* junk;
|
||||
|
||||
if ((mbrPart < 0) || (mbrPart > 3)) {
|
||||
printf("MBR partition %d is out of range; omitting it.\n", mbrPart + 1);
|
||||
@@ -1561,7 +1608,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
||||
do {
|
||||
printf("Enter an MBR hex code (default %02X): ",
|
||||
typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256);
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%x", &typeCode);
|
||||
if (line[0] == '\n')
|
||||
typeCode = partitions[gptPart].GetHexType() / 256;
|
||||
@@ -1586,6 +1633,7 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
||||
// the GPT data, and then exit.
|
||||
int GPTData::XFormToMBR(void) {
|
||||
char line[255];
|
||||
char* junk;
|
||||
int i, j, numParts, numConverted = 0;
|
||||
uint32_t partNums[4];
|
||||
|
||||
@@ -1601,7 +1649,7 @@ int GPTData::XFormToMBR(void) {
|
||||
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);
|
||||
junk = 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
|
||||
@@ -1626,6 +1674,7 @@ int GPTData::XFormToMBR(void) {
|
||||
void GPTData::MakeHybrid(void) {
|
||||
uint32_t partNums[3];
|
||||
char line[255];
|
||||
char* junk;
|
||||
int numParts, numConverted = 0, i, j, typeCode, mbrNum;
|
||||
char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe)
|
||||
char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
|
||||
@@ -1638,7 +1687,7 @@ void GPTData::MakeHybrid(void) {
|
||||
// hybrid MBR....
|
||||
printf("Type from one to three GPT partition numbers, separated by spaces, to be\n"
|
||||
"added to the hybrid MBR, in sequence: ");
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
numParts = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]);
|
||||
|
||||
if (numParts > 0) {
|
||||
@@ -1690,7 +1739,7 @@ void GPTData::MakeHybrid(void) {
|
||||
printf("Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): ");
|
||||
// Comment on above: Mac OS treats disks with more than one
|
||||
// 0xEE MBR partition as MBR disks, not as GPT disks.
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%x", &typeCode);
|
||||
if (line[0] == '\n')
|
||||
typeCode = 0;
|
||||
@@ -1951,8 +2000,8 @@ int GPTData::Align(uint64_t* sector) {
|
||||
// Otherwise, notify the user that it couldn't be done....
|
||||
if (sectorOK == 1) {
|
||||
printf("Information: Moved requested sector from %llu to %llu for\n"
|
||||
"alignment purposes. Use 'l' on the experts' menu to adjust alignment.\n",
|
||||
original, *sector);
|
||||
"alignment purposes. Use 'l' on the experts' menu to adjust alignment.\n",
|
||||
(unsigned long long) original, (unsigned long long) *sector);
|
||||
} else {
|
||||
printf("Information: Sector not aligned on %d-sector boundary and could not be moved.\n"
|
||||
"If you're using a Western Digital Advanced Format or similar disk with\n"
|
||||
|
||||
2
gpt.h
2
gpt.h
@@ -61,6 +61,7 @@ protected:
|
||||
uint32_t blockSize; // device block size
|
||||
uint64_t diskSize; // size of device, in blocks
|
||||
GPTValidity state; // is GPT valid?
|
||||
int justLooking; // Set to 1 if program launched with "-l" or if read-only
|
||||
int mainCrcOk;
|
||||
int secondCrcOk;
|
||||
int mainPartsCrcOk;
|
||||
@@ -135,6 +136,7 @@ public:
|
||||
void MakeProtectiveMBR(void) {protectiveMBR.MakeProtectiveMBR();}
|
||||
int Align(uint64_t* sector);
|
||||
void SetAlignment(int n) {sectorAlignment = n;}
|
||||
void JustLooking(int i = 1) {justLooking = i;}
|
||||
|
||||
// Return data about the GPT structures....
|
||||
int GetPartRange(uint32_t* low, uint32_t* high);
|
||||
|
||||
@@ -187,6 +187,7 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
|
||||
// Change the type code on the partition.
|
||||
void GPTPart::ChangeType(void) {
|
||||
char typeName[255], line[255];
|
||||
char* junk;
|
||||
int typeNum = 0xFFFF;
|
||||
// uint16_t typeNum = 0xFFFF;
|
||||
GUIDData newType;
|
||||
@@ -195,7 +196,7 @@ void GPTPart::ChangeType(void) {
|
||||
// printf("Current type is '%s'\n", typeHelper.GUIDToName(partitionType, typeName));
|
||||
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
|
||||
printf("Hex code (L to show codes, 0 to enter raw code): ");
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%X", &typeNum);
|
||||
if ((line[0] == 'L') || (line[0] == 'l'))
|
||||
typeHelper.ShowTypes();
|
||||
@@ -215,6 +216,7 @@ void GPTPart::ChangeType(void) {
|
||||
// string. This function creates a simple-minded copy for this.
|
||||
void GPTPart::SetName(unsigned char* theName) {
|
||||
char newName[NAME_SIZE]; // New name
|
||||
char* junk;
|
||||
int i;
|
||||
|
||||
// Blank out new name string, just to be on the safe side....
|
||||
@@ -223,7 +225,7 @@ void GPTPart::SetName(unsigned char* theName) {
|
||||
|
||||
if (theName == NULL) { // No name specified, so get one from the user
|
||||
printf("Enter name: ");
|
||||
fgets(newName, NAME_SIZE / 2, stdin);
|
||||
junk = fgets(newName, NAME_SIZE / 2, stdin);
|
||||
|
||||
// Input is likely to include a newline, so remove it....
|
||||
i = strlen(newName);
|
||||
|
||||
4
mbr.cc
4
mbr.cc
@@ -289,7 +289,9 @@ void MBRData::WriteMBRData(int fd) {
|
||||
|
||||
// Now write that data structure...
|
||||
lseek64(fd, 0, SEEK_SET);
|
||||
write(fd, &tempMBR, 512);
|
||||
if (write(fd, &tempMBR, 512) != 512) {
|
||||
fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
|
||||
} // if
|
||||
|
||||
// Reverse the byte order back, if necessary
|
||||
if (IsLittleEndian() == 0) {
|
||||
|
||||
113
support.cc
113
support.cc
@@ -20,6 +20,13 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
// As of 1/2010, BLKPBSZGET is very new, so I'm explicitly defining it if
|
||||
// it's not already defined. This should become unnecessary in the future.
|
||||
// Note that this is a Linux-only ioctl....
|
||||
#ifndef BLKPBSZGET
|
||||
#define BLKPBSZGET _IO(0x12,123)
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Get a numeric value from the user, between low and high (inclusive).
|
||||
@@ -30,12 +37,13 @@ using namespace std;
|
||||
int GetNumber(int low, int high, int def, const char prompt[]) {
|
||||
int response, num;
|
||||
char line[255];
|
||||
char* junk;
|
||||
|
||||
if (low != high) { // bother only if low and high differ...
|
||||
response = low - 1; // force one loop by setting response outside range
|
||||
while ((response < low) || (response > high)) {
|
||||
printf("%s", prompt);
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
num = sscanf(line, "%d", &response);
|
||||
if (num == 1) { // user provided a response
|
||||
if ((response < low) || (response > high))
|
||||
@@ -55,10 +63,11 @@ int GetNumber(int low, int high, int def, const char prompt[]) {
|
||||
char GetYN(void) {
|
||||
char line[255];
|
||||
char response = '\0';
|
||||
char* junk;
|
||||
|
||||
while ((response != 'Y') && (response != 'N')) {
|
||||
printf("(Y/N): ");
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &response);
|
||||
if (response == 'y') response = 'Y';
|
||||
if (response == 'n') response = 'N';
|
||||
@@ -80,11 +89,12 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[])
|
||||
uint64_t mult = 1;
|
||||
char suffix;
|
||||
char line[255];
|
||||
char* junk;
|
||||
|
||||
response = low - 1; // Ensure one pass by setting a too-low initial value
|
||||
while ((response < low) || (response > high)) {
|
||||
printf("%s", prompt);
|
||||
fgets(line, 255, stdin);
|
||||
junk = fgets(line, 255, stdin);
|
||||
|
||||
// Remove leading spaces, if present
|
||||
while (line[0] == ' ')
|
||||
@@ -189,16 +199,16 @@ char* BytesToSI(uint64_t size, char theValue[]) {
|
||||
// returns an error condition, print a warning but return a value of SECTOR_SIZE
|
||||
// (512)..
|
||||
int GetBlockSize(int fd) {
|
||||
int err, result;
|
||||
int err = -1, result;
|
||||
|
||||
#ifdef __APPLE__
|
||||
err = ioctl(fd, DKIOCGETBLOCKSIZE, &result);
|
||||
#else
|
||||
#endif
|
||||
#ifdef __FreeBSD__
|
||||
err = ioctl(fd, DIOCGSECTORSIZE, &result);
|
||||
#else
|
||||
err = ioctl(fd, BLKSSZGET, &result);
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
err = ioctl(fd, BLKSSZGET, &result);
|
||||
#endif
|
||||
|
||||
if (err == -1) {
|
||||
@@ -221,51 +231,78 @@ int GetBlockSize(int fd) {
|
||||
return (result);
|
||||
} // GetBlockSize()
|
||||
|
||||
// Return the partition alignment value in sectors. Right now this works
|
||||
// only for Linux 2.6.32 and later, since I can't find equivalent ioctl()s
|
||||
// for OS X or FreeBSD, and the Linux ioctl is new
|
||||
int FindAlignment(int fd) {
|
||||
int err = -2, result = 8, physicalSectorSize = 4096;
|
||||
|
||||
#if defined (__linux__) && defined (BLKPBSZGET)
|
||||
err = ioctl(fd, BLKPBSZGET, &physicalSectorSize);
|
||||
// printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize);
|
||||
#else
|
||||
err = -1;
|
||||
#endif
|
||||
|
||||
if (err < 0) {
|
||||
result = 8;
|
||||
} else {
|
||||
result = physicalSectorSize / GetBlockSize(fd);
|
||||
} // if/else
|
||||
return result;
|
||||
} // FindAlignment(int)
|
||||
|
||||
// The same as FindAlignment(int), but opens and closes a device by filename
|
||||
int FindAlignment(char deviceFilename[]) {
|
||||
int fd;
|
||||
int retval = 1;
|
||||
|
||||
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
|
||||
retval = FindAlignment(fd);
|
||||
close(fd);
|
||||
} // if
|
||||
return retval;
|
||||
} // FindAlignment(char)
|
||||
|
||||
// Return a plain-text name for a partition type.
|
||||
// Convert a GUID to a string representation, suitable for display
|
||||
// to humans....
|
||||
char* GUIDToStr(struct GUIDData theGUID, char* theString) {
|
||||
uint64_t block;
|
||||
unsigned long long blocks[11], block;
|
||||
|
||||
if (theString != NULL) {
|
||||
block = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF));
|
||||
sprintf(theString, "%08llX-", (unsigned long long) block);
|
||||
block = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32;
|
||||
sprintf(theString, "%s%04llX-", theString, (unsigned long long) block);
|
||||
block = (theGUID.data1 & UINT64_C(0xFFFF000000000000)) >> 48;
|
||||
sprintf(theString, "%s%04llX-", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x00000000000000FF));
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x000000000000FF00)) >> 8;
|
||||
sprintf(theString, "%s%02llX-", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x0000000000FF0000)) >> 16;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x00000000FF000000)) >> 24;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x000000FF00000000)) >> 32;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x0000FF0000000000)) >> 40;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x00FF000000000000)) >> 48;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0xFF00000000000000)) >> 56;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
} // if
|
||||
if (theString != NULL) {
|
||||
blocks[0] = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF));
|
||||
blocks[1] = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32;
|
||||
blocks[2] = (theGUID.data1 & UINT64_C(0xFFFF000000000000)) >> 48;
|
||||
blocks[3] = (theGUID.data2 & UINT64_C(0x00000000000000FF));
|
||||
blocks[4] = (theGUID.data2 & UINT64_C(0x000000000000FF00)) >> 8;
|
||||
blocks[5] = (theGUID.data2 & UINT64_C(0x0000000000FF0000)) >> 16;
|
||||
blocks[6] = (theGUID.data2 & UINT64_C(0x00000000FF000000)) >> 24;
|
||||
blocks[7] = (theGUID.data2 & UINT64_C(0x000000FF00000000)) >> 32;
|
||||
blocks[8] = (theGUID.data2 & UINT64_C(0x0000FF0000000000)) >> 40;
|
||||
blocks[9] = (theGUID.data2 & UINT64_C(0x00FF000000000000)) >> 48;
|
||||
blocks[10] = (theGUID.data2 & UINT64_C(0xFF00000000000000)) >> 56;
|
||||
sprintf(theString,
|
||||
"%08llX-%04llX-%04llX-%02llX%02llX-%02llX%02llX%02llX%02llX%02llX%02llX",
|
||||
blocks[0], blocks[1], blocks[2], blocks[3], blocks[4], blocks[5],
|
||||
blocks[6], blocks[7], blocks[8], blocks[9], blocks[10]);
|
||||
} // if
|
||||
return theString;
|
||||
} // GUIDToStr()
|
||||
|
||||
// Get a GUID from the user
|
||||
GUIDData GetGUID(void) {
|
||||
uint64_t part1, part2, part3, part4, part5;
|
||||
unsigned long long part1, part2, part3, part4, part5;
|
||||
int entered = 0;
|
||||
char temp[255], temp2[255];
|
||||
char* junk;
|
||||
GUIDData theGUID;
|
||||
|
||||
printf("\nA GUID is entered in five segments of from two to six bytes, with\n"
|
||||
"dashes between segments.\n");
|
||||
printf("Enter the entire GUID, a four-byte hexadecimal number for the first segment, or\n"
|
||||
"'R' to generate the entire GUID randomly: ");
|
||||
fgets(temp, 255, stdin);
|
||||
junk = fgets(temp, 255, stdin);
|
||||
|
||||
// If user entered 'r' or 'R', generate GUID randomly....
|
||||
if ((temp[0] == 'r') || (temp[0] == 'R')) {
|
||||
@@ -308,17 +345,17 @@ GUIDData GetGUID(void) {
|
||||
if (entered == 0) {
|
||||
sscanf(temp, "%llx", &part1);
|
||||
printf("Enter a two-byte hexadecimal number for the second segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part2);
|
||||
printf("Enter a two-byte hexadecimal number for the third segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part3);
|
||||
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
|
||||
printf("Enter a two-byte hexadecimal number for the fourth segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part4);
|
||||
printf("Enter a six-byte hexadecimal number for the fifth segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
junk = fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part5);
|
||||
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
|
||||
((part4 & UINT64_C(0x00000000000000FF)) << 8) +
|
||||
|
||||
@@ -60,6 +60,8 @@ char GetYN(void);
|
||||
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, char prompt[]);
|
||||
char* BytesToSI(uint64_t size, char theValue[]);
|
||||
int GetBlockSize(int fd);
|
||||
int FindAlignment(int fd);
|
||||
int FindAlignment(char device[]);
|
||||
char* GUIDToStr(struct GUIDData theGUID, char* theString);
|
||||
GUIDData GetGUID(void);
|
||||
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
|
||||
|
||||
Reference in New Issue
Block a user