Early support for larger-than-512-byte sectors and even earlier support
for sgdisk program. (The latter is just proof-of-concept at this point; it doesn't do anything useful.)
This commit is contained in:
@@ -1,6 +1,13 @@
|
||||
0.5.3 (1/??/2009):
|
||||
0.6.0 (1/??/2009):
|
||||
------------------
|
||||
|
||||
- Added support for disks with other than 512-byte sectors.
|
||||
|
||||
- Created embryonic sgdisk program.
|
||||
|
||||
0.5.3 (1/4/2009):
|
||||
-----------------
|
||||
|
||||
- Fixed bug in display of GUIDs when compiled with some versions of GCC.
|
||||
|
||||
- Eliminated warnings caused by additional checks in latest versions of
|
||||
|
||||
3
Makefile
3
Makefile
@@ -15,6 +15,9 @@ DEPEND= makedepend $(CFLAGS)
|
||||
gdisk: $(LIB_OBJS) gdisk.o
|
||||
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk
|
||||
|
||||
sgdisk: $(LIB_OBJS) sgdisk.o
|
||||
$(CXX) $(LIB_OBJS) sgdisk.o -o sgdisk
|
||||
|
||||
wipegpt: $(LIB_OBJS) wipegpt.o
|
||||
$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
|
||||
|
||||
|
||||
8
bsd.cc
8
bsd.cc
@@ -63,7 +63,7 @@ int BSDData::ReadBSDData(char* device, uint64_t startSector, uint64_t endSector)
|
||||
// Load the BSD disklabel data from an already-opened disk
|
||||
// file, starting with the specified sector number.
|
||||
void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
|
||||
uint8_t buffer[2048]; // I/O buffer
|
||||
uint8_t buffer[4096]; // I/O buffer
|
||||
int i, err, foundSig = 0, bigEnd = 0;
|
||||
int relative = 0; // assume absolute partition sector numbering
|
||||
uint32_t realSig;
|
||||
@@ -74,10 +74,10 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
|
||||
labelFirstLBA = startSector;
|
||||
labelLastLBA = endSector;
|
||||
|
||||
// Read two sectors into memory; we'll extract data from
|
||||
// Read eight sectors into memory; we'll extract data from
|
||||
// this buffer. (Done to work around FreeBSD limitation)
|
||||
lseek64(fd, startSector * 512, SEEK_SET);
|
||||
err = read(fd, buffer, 2048);
|
||||
lseek64(fd, startSector * GetBlockSize(fd), SEEK_SET);
|
||||
err = read(fd, buffer, 4096);
|
||||
|
||||
// Do some strangeness to support big-endian architectures...
|
||||
bigEnd = (IsLittleEndian() == 0);
|
||||
|
||||
5
gdisk.cc
5
gdisk.cc
@@ -4,7 +4,7 @@
|
||||
//
|
||||
// by Rod Smith, project began February 2009
|
||||
|
||||
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
||||
/* This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
|
||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
||||
|
||||
//#include <iostream>
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "support.h"
|
||||
|
||||
// Function prototypes....
|
||||
// int ReadPartitions(char* filename, struct GPTData* theGPT);
|
||||
void MainMenu(char* filename, struct GPTData* theGPT);
|
||||
void ShowCommands(void);
|
||||
void ExpertsMenu(char* filename, struct GPTData* theGPT);
|
||||
@@ -29,7 +28,7 @@ int main(int argc, char* argv[]) {
|
||||
int doMore = 1;
|
||||
char* device = NULL;
|
||||
|
||||
printf("GPT fdisk (gdisk) version 0.5.3\n\n");
|
||||
printf("GPT fdisk (gdisk) version 0.5.4-pre1\n\n");
|
||||
|
||||
if (argc == 2) { // basic usage
|
||||
if (SizesOK()) {
|
||||
|
||||
99
gpt.cc
99
gpt.cc
@@ -49,6 +49,7 @@ GPTData::GPTData(void) {
|
||||
bsdFound = 0;
|
||||
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
|
||||
srand((unsigned int) time(NULL));
|
||||
mainHeader.numParts = 0;
|
||||
SetGPTSize(NUM_GPT_ENTRIES);
|
||||
} // GPTData default constructor
|
||||
|
||||
@@ -68,6 +69,7 @@ GPTData::GPTData(char* filename) {
|
||||
bsdFound = 0;
|
||||
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
|
||||
srand((unsigned int) time(NULL));
|
||||
mainHeader.numParts = 0;
|
||||
LoadPartitions(filename);
|
||||
} // GPTData(char* filename) constructor
|
||||
|
||||
@@ -601,9 +603,9 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
uint32_t newCRC, sizeOfParts;
|
||||
|
||||
// Seek to and read the main GPT header
|
||||
lseek64(fd, 512, SEEK_SET);
|
||||
if (read(fd, &mainHeader, 512) != 512) { // read main GPT header
|
||||
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
|
||||
lseek64(fd, blockSize, SEEK_SET);
|
||||
if (myRead(fd, (char*) &mainHeader, 512) != 512) { // read main GPT header
|
||||
fprintf(stderr, "Warning! Error %d reading main GPT header!\n", errno);
|
||||
} // if
|
||||
mainCrcOk = CheckHeaderCRC(&mainHeader);
|
||||
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
|
||||
@@ -618,19 +620,19 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
if (mainHeader.backupLBA < diskSize) {
|
||||
seekTo = mainHeader.backupLBA * blockSize;
|
||||
} else {
|
||||
seekTo = (diskSize * blockSize) - UINT64_C(512);
|
||||
seekTo = (diskSize * blockSize) - blockSize;
|
||||
printf("Warning! Disk size is smaller than the main header indicates! Loading\n"
|
||||
"secondary header from the last sector of the disk! You should use 'v' to\n"
|
||||
"verify disk integrity, and perhaps options on the experts' menu to repair\n"
|
||||
"the disk.\n");
|
||||
} // else
|
||||
} else {
|
||||
seekTo = (diskSize * blockSize) - UINT64_C(512);
|
||||
seekTo = (diskSize * blockSize) - blockSize;
|
||||
} // if/else (mainCrcOk)
|
||||
|
||||
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
|
||||
if (read(fd, &secondHeader, 512) != 512) { // read secondary GPT header
|
||||
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno);
|
||||
if (myRead(fd, (char*) &secondHeader, 512) != 512) { // read secondary GPT header
|
||||
fprintf(stderr, "Warning! Error %d reading secondary GPT header!\n", errno);
|
||||
} // if
|
||||
secondCrcOk = CheckHeaderCRC(&secondHeader);
|
||||
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
|
||||
@@ -681,7 +683,7 @@ int GPTData::ForceLoadGPTData(int fd) {
|
||||
if ((lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) && (secondCrcOk)) {
|
||||
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
|
||||
storage = (char*) malloc(sizeOfParts);
|
||||
if (read(fd, storage, sizeOfParts) != sizeOfParts) {
|
||||
if (myRead(fd, storage, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Error %d reading backup partition table!\n", errno);
|
||||
} // if
|
||||
newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
|
||||
@@ -716,7 +718,7 @@ int GPTData::LoadMainTable(void) {
|
||||
// matches the stored value
|
||||
lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET);
|
||||
sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
|
||||
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
|
||||
if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Error %d when loading the main partition table!\n", errno);
|
||||
} // if
|
||||
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
|
||||
@@ -740,7 +742,7 @@ void GPTData::LoadSecondTableAsMain(void) {
|
||||
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
|
||||
SetGPTSize(secondHeader.numParts);
|
||||
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
|
||||
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
|
||||
if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Read error %d! Misbehavior now likely!\n", errno);
|
||||
} // if
|
||||
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
|
||||
@@ -852,15 +854,21 @@ int GPTData::SaveGPTData(void) {
|
||||
protectiveMBR.WriteMBRData(fd);
|
||||
|
||||
// Now write the main GPT header...
|
||||
if (allOK)
|
||||
if (write(fd, &mainHeader, 512) == -1)
|
||||
allOK = 0;
|
||||
if (allOK) {
|
||||
if (lseek64(fd, blockSize, SEEK_SET) != (off_t) -1) {
|
||||
if (myWrite(fd, (char*) &mainHeader, 512) == -1)
|
||||
allOK = 0;
|
||||
} else allOK = 0; // if (lseek64()...)
|
||||
} // if (allOK)
|
||||
|
||||
// Now write the main partition tables...
|
||||
if (allOK) {
|
||||
if (write(fd, partitions, GPT_SIZE * numParts) == -1)
|
||||
offset = mainHeader.partitionEntriesLBA * blockSize;
|
||||
if (lseek64(fd, offset, SEEK_SET) != (off_t) - 1) {
|
||||
if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
|
||||
allOK = 0;
|
||||
} // if
|
||||
} else allOK = 0; // if (lseek64()...)
|
||||
} // if (allOK)
|
||||
|
||||
// Now seek to near the end to write the secondary GPT....
|
||||
if (allOK) {
|
||||
@@ -872,14 +880,19 @@ int GPTData::SaveGPTData(void) {
|
||||
} // if
|
||||
|
||||
// Now write the secondary partition tables....
|
||||
if (allOK)
|
||||
if (write(fd, partitions, GPT_SIZE * numParts) == -1)
|
||||
if (allOK) {
|
||||
if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
|
||||
allOK = 0;
|
||||
} // if (allOK)
|
||||
|
||||
// Now write the secondary GPT header...
|
||||
if (allOK)
|
||||
if (write(fd, &secondHeader, 512) == -1)
|
||||
allOK = 0;
|
||||
if (allOK) {
|
||||
offset = mainHeader.backupLBA * blockSize;
|
||||
if (lseek64(fd, offset, SEEK_SET) != (off_t) - 1) {
|
||||
if (myWrite(fd, (char*) &secondHeader, 512) == -1)
|
||||
allOK = 0;
|
||||
} else allOK = 0; // if (lseek64()...)
|
||||
} // if (allOK)
|
||||
|
||||
// re-read the partition table
|
||||
if (allOK) {
|
||||
@@ -944,17 +957,17 @@ int GPTData::SaveGPTBackup(char* filename) {
|
||||
|
||||
// Now write the main GPT header...
|
||||
if (allOK)
|
||||
if (write(fd, &mainHeader, 512) == -1)
|
||||
if (myWrite(fd, (char*) &mainHeader, 512) == -1)
|
||||
allOK = 0;
|
||||
|
||||
// Now write the secondary GPT header...
|
||||
if (allOK)
|
||||
if (write(fd, &secondHeader, 512) == -1)
|
||||
if (myWrite(fd, (char*) &secondHeader, 512) == -1)
|
||||
allOK = 0;
|
||||
|
||||
// Now write the main partition tables...
|
||||
if (allOK) {
|
||||
if (write(fd, partitions, GPT_SIZE * numParts) == -1)
|
||||
if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
|
||||
allOK = 0;
|
||||
} // if
|
||||
|
||||
@@ -997,7 +1010,7 @@ int GPTData::LoadGPTBackup(char* filename) {
|
||||
|
||||
// Load the main GPT header, check its vaility, and set the GPT
|
||||
// size based on the data
|
||||
if (read(fd, &mainHeader, 512)) {
|
||||
if (myRead(fd, (char*) &mainHeader, 512)) {
|
||||
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
|
||||
} // if
|
||||
mainCrcOk = CheckHeaderCRC(&mainHeader);
|
||||
@@ -1009,7 +1022,7 @@ int GPTData::LoadGPTBackup(char* filename) {
|
||||
|
||||
// Load the backup GPT header in much the same way as the main
|
||||
// GPT header....
|
||||
if (read(fd, &secondHeader, 512) != 512) {
|
||||
if (myRead(fd, (char*) &secondHeader, 512) != 512) {
|
||||
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
|
||||
} // if
|
||||
secondCrcOk = CheckHeaderCRC(&secondHeader);
|
||||
@@ -1045,7 +1058,7 @@ int GPTData::LoadGPTBackup(char* filename) {
|
||||
// Load main partition table, and record whether its CRC
|
||||
// matches the stored value
|
||||
sizeOfParts = numParts * sizeOfEntries;
|
||||
if (read(fd, partitions, sizeOfParts) != sizeOfParts) {
|
||||
if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
|
||||
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
|
||||
} // if
|
||||
|
||||
@@ -1109,6 +1122,7 @@ void GPTData::DisplayGPTData(void) {
|
||||
BytesToSI(diskSize * blockSize, sizeInSI);
|
||||
printf("Disk %s: %llu sectors, %s\n", device,
|
||||
(unsigned long long) diskSize, sizeInSI);
|
||||
printf("Logical sector size: %d bytes\n", blockSize);
|
||||
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 %llu, last usable sector is %llu\n",
|
||||
@@ -1302,8 +1316,9 @@ 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, sum;
|
||||
int fd, i, sum, tableSize;
|
||||
char blankSector[512], goOn = 'Y', blank = 'N';
|
||||
char* emptyTable;
|
||||
|
||||
for (i = 0; i < 512; i++) {
|
||||
blankSector[i] = '\0';
|
||||
@@ -1326,24 +1341,24 @@ int GPTData::DestroyGPT(int prompt) {
|
||||
} // if
|
||||
#endif
|
||||
if (fd != -1) {
|
||||
lseek64(fd, mainHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
|
||||
if (write(fd, blankSector, 512) != 512) { // blank it out
|
||||
lseek64(fd, mainHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
|
||||
if (myWrite(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++)
|
||||
sum += write(fd, blankSector, 512);
|
||||
if (sum != 512 * GetBlocksInPartTable())
|
||||
lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
|
||||
tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
|
||||
emptyTable = (char*) malloc(tableSize);
|
||||
for (i = 0; i < tableSize; i++)
|
||||
emptyTable[i] = (char) 0;
|
||||
sum = myWrite(fd, emptyTable, tableSize);
|
||||
if (sum != tableSize)
|
||||
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++)
|
||||
sum += write(fd, blankSector, 512);
|
||||
if (sum != 512 * GetBlocksInPartTable())
|
||||
lseek64(fd, secondHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
|
||||
sum = myWrite(fd, emptyTable, tableSize);
|
||||
if (sum != tableSize)
|
||||
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
|
||||
if (write(fd, blankSector, 512) != 512) { // blank it out
|
||||
lseek64(fd, secondHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
|
||||
if (myWrite(fd, blankSector, 512) != 512) { // blank it out
|
||||
fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
|
||||
} // if
|
||||
if (prompt) {
|
||||
@@ -1357,7 +1372,7 @@ int GPTData::DestroyGPT(int prompt) {
|
||||
// structures).
|
||||
if (blank == 'Y') {
|
||||
lseek64(fd, 0, SEEK_SET);
|
||||
if (write(fd, blankSector, 512) != 512) { // blank it out
|
||||
if (myWrite(fd, blankSector, 512) != 512) { // blank it out
|
||||
fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
|
||||
} // if
|
||||
} else {
|
||||
|
||||
2
gpt.h
2
gpt.h
@@ -145,8 +145,6 @@ public:
|
||||
uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}
|
||||
uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
|
||||
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
|
||||
uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
|
||||
mainHeader.sizeOfPartitionEntries) / blockSize;}
|
||||
uint32_t CountParts(void);
|
||||
int GetAlignment(void) {return sectorAlignment;}
|
||||
|
||||
|
||||
6
mbr.cc
6
mbr.cc
@@ -98,7 +98,7 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
||||
EmptyMBR(0);
|
||||
|
||||
err = lseek64(fd, 0, SEEK_SET);
|
||||
err = read(fd, &tempMBR, 512);
|
||||
err = myRead(fd, (char*) &tempMBR, 512);
|
||||
for (i = 0; i < 440; i++)
|
||||
code[i] = tempMBR.code[i];
|
||||
diskSignature = tempMBR.diskSignature;
|
||||
@@ -202,7 +202,7 @@ int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
|
||||
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
|
||||
partNum = -1;
|
||||
}
|
||||
if (read(fd, &ebr, 512) != 512) { // Load the data....
|
||||
if (myRead(fd, (char*) &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;
|
||||
@@ -289,7 +289,7 @@ void MBRData::WriteMBRData(int fd) {
|
||||
|
||||
// Now write that data structure...
|
||||
lseek64(fd, 0, SEEK_SET);
|
||||
if (write(fd, &tempMBR, 512) != 512) {
|
||||
if (myWrite(fd, (char*) &tempMBR, 512) != 512) {
|
||||
fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
|
||||
} // if
|
||||
|
||||
|
||||
464
sgdisk.cc
Normal file
464
sgdisk.cc
Normal file
@@ -0,0 +1,464 @@
|
||||
// sgdisk.cc
|
||||
// Program modelled after Linux sfdisk, but it manipulates GPT partitions
|
||||
// rather than MBR partitions. This is effectively a new user interface
|
||||
// to my gdisk program.
|
||||
//
|
||||
// by Rod Smith, project began February 2009
|
||||
|
||||
/* This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
|
||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
||||
|
||||
//#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include "mbr.h"
|
||||
#include "gpt.h"
|
||||
#include "support.h"
|
||||
|
||||
#define MAX_OPTIONS 50
|
||||
|
||||
// Function prototypes....
|
||||
/* void MainMenu(char* filename, struct GPTData* theGPT);
|
||||
void ShowCommands(void);
|
||||
void ExpertsMenu(char* filename, struct GPTData* theGPT);
|
||||
void ShowExpertCommands(void);
|
||||
void RecoveryMenu(char* filename, struct GPTData* theGPT);
|
||||
void ShowRecoveryCommands(void); */
|
||||
|
||||
enum Commands { NONE, LIST, VERIFY };
|
||||
|
||||
struct Options {
|
||||
Commands theCommand;
|
||||
char* theArgument;
|
||||
}; // struct Options
|
||||
|
||||
int verbose_flag;
|
||||
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{"verify", no_argument, NULL, 'v'},
|
||||
{"list", no_argument, NULL, 'l'},
|
||||
{0, 0, NULL, 0}
|
||||
};
|
||||
|
||||
int ParseOptions(int argc, char* argv[], Options* theOptions, char** device);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
GPTData theGPT;
|
||||
int doMore = 1, opt, i, numOptions = 0;
|
||||
char* device = NULL;
|
||||
Options theOptions[MAX_OPTIONS];
|
||||
|
||||
printf("GPT fdisk (sgdisk) version 0.5.4-pre1\n\n");
|
||||
numOptions = ParseOptions(argc, argv, theOptions, &device);
|
||||
|
||||
if (device != NULL) {
|
||||
if (theGPT.LoadPartitions(device)) {
|
||||
for (i = 0; i < numOptions; i++) {
|
||||
switch (theOptions[i].theCommand) {
|
||||
case LIST:
|
||||
theGPT.JustLooking();
|
||||
theGPT.DisplayGPTData();
|
||||
break;
|
||||
case VERIFY:
|
||||
theGPT.JustLooking();
|
||||
theGPT.Verify();
|
||||
break;
|
||||
case NONE:
|
||||
printf("Usage: %s {-lv} device\n", argv[0]);
|
||||
break;
|
||||
} // switch
|
||||
} // for
|
||||
} // if loaded OK
|
||||
} // if (device != NULL)
|
||||
|
||||
return 0;
|
||||
} // main
|
||||
|
||||
// Parse command-line options. Returns the number of arguments retrieved
|
||||
int ParseOptions(int argc, char* argv[], Options* theOptions, char** device) {
|
||||
int opt, i, numOptions = 0;
|
||||
int verbose_flag;
|
||||
|
||||
// Use getopt() to extract commands and their arguments
|
||||
/* getopt_long stores the option index here. */
|
||||
int option_index = 0;
|
||||
|
||||
// c = getopt_long (argc, argv, "abc:d:f:",
|
||||
// long_options, &option_index);
|
||||
|
||||
while (((opt = getopt_long(argc, argv, "vl", long_options, &option_index)) != -1)
|
||||
&& (numOptions < MAX_OPTIONS)) {
|
||||
printf("opt is %c, option_index is %d\n", opt, option_index);
|
||||
switch (opt) {
|
||||
case 'l':
|
||||
printf("Entering list option, numOptions = %d!\n", numOptions);
|
||||
theOptions[numOptions].theCommand = LIST;
|
||||
theOptions[numOptions++].theArgument = NULL;
|
||||
break;
|
||||
case 'v':
|
||||
theOptions[numOptions].theCommand = VERIFY;
|
||||
theOptions[numOptions++].theArgument = NULL;
|
||||
break;
|
||||
default:
|
||||
printf("Default switch; opt is %c\n", opt);
|
||||
break;
|
||||
// abort();
|
||||
} // switch
|
||||
} // while
|
||||
|
||||
// Find non-option arguments. If the user types a legal command, there
|
||||
// will be only one of these: The device filename....
|
||||
opt = 0;
|
||||
printf("Searching for device filename; optind is %d\n", optind);
|
||||
for (i = optind; i < argc; i++) {
|
||||
*device = argv[i];
|
||||
printf("Setting device to %s\n", argv[i]);
|
||||
opt++;
|
||||
} // for
|
||||
if (opt > 1) {
|
||||
fprintf(stderr, "Warning! Found stray unrecognized arguments! Program may misbehave!\n");
|
||||
} // if
|
||||
|
||||
return numOptions;
|
||||
} // ParseOptions()
|
||||
|
||||
/* // Accept a command and execute it. Returns only when the user
|
||||
// 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): ");
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
case 'b': case 'B':
|
||||
printf("Enter backup filename to save: ");
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%s", (char*) &buFile);
|
||||
theGPT->SaveGPTBackup(buFile);
|
||||
break;
|
||||
case 'c': case 'C':
|
||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
||||
theGPT->SetName(theGPT->GetPartNum());
|
||||
else
|
||||
printf("No partitions\n");
|
||||
break;
|
||||
case 'd': case 'D':
|
||||
theGPT->DeletePartition();
|
||||
break;
|
||||
case 'i': case 'I':
|
||||
theGPT->ShowDetails();
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
typeHelper.ShowTypes();
|
||||
break;
|
||||
case 'n': case 'N':
|
||||
theGPT->CreatePartition();
|
||||
break;
|
||||
case 'o': case 'O':
|
||||
printf("This option deletes all partitions and creates a new "
|
||||
"protective MBR.\nProceed? ");
|
||||
if (GetYN() == 'Y') {
|
||||
theGPT->ClearGPTData();
|
||||
theGPT->MakeProtectiveMBR();
|
||||
} // if
|
||||
break;
|
||||
case 'p': case 'P':
|
||||
theGPT->DisplayGPTData();
|
||||
break;
|
||||
case 'q': case 'Q':
|
||||
goOn = 0;
|
||||
break;
|
||||
case 'r': case 'R':
|
||||
RecoveryMenu(filename, theGPT);
|
||||
goOn = 0;
|
||||
break;
|
||||
case 's': case 'S':
|
||||
theGPT->SortGPT();
|
||||
printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
|
||||
break;
|
||||
case 't': case 'T':
|
||||
theGPT->ChangePartType();
|
||||
break;
|
||||
case 'v': case 'V':
|
||||
if (theGPT->Verify() > 0) { // problems found
|
||||
printf("You may be able to correct the problems by using options on the experts\n"
|
||||
"menu (press 'x' at the command prompt). Good luck!\n");
|
||||
} // if
|
||||
break;
|
||||
case 'w': case 'W':
|
||||
if (theGPT->SaveGPTData() == 1)
|
||||
goOn = 0;
|
||||
break;
|
||||
case 'x': case 'X':
|
||||
ExpertsMenu(filename, theGPT);
|
||||
goOn = 0;
|
||||
break;
|
||||
default:
|
||||
ShowCommands();
|
||||
break;
|
||||
} // switch
|
||||
} while (goOn);
|
||||
} // MainMenu()
|
||||
|
||||
void ShowCommands(void) {
|
||||
printf("b\tback up GPT data to a file\n");
|
||||
printf("c\tchange a partition's name\n");
|
||||
printf("d\tdelete a partition\n");
|
||||
printf("i\tshow detailed information on a partition\n");
|
||||
printf("l\tlist known partition types\n");
|
||||
printf("n\tadd a new partition\n");
|
||||
printf("o\tcreate a new empty GUID partition table (GPT)\n");
|
||||
printf("p\tprint the partition table\n");
|
||||
printf("q\tquit without saving changes\n");
|
||||
printf("r\trecovery and transformation options (experts only)\n");
|
||||
printf("s\tsort partitions\n");
|
||||
printf("t\tchange a partition's type code\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");
|
||||
} // ShowCommands()
|
||||
|
||||
// Accept a recovery & transformation menu command. Returns only when the user
|
||||
// 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): ");
|
||||
junk = 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: ");
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%s", (char*) &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];
|
||||
char* junk;
|
||||
PartTypes typeHelper;
|
||||
uint32_t pn;
|
||||
uint32_t temp1, temp2;
|
||||
int goOn = 1;
|
||||
|
||||
do {
|
||||
printf("\nExpert command (? for help): ");
|
||||
junk = fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
case 'a': case 'A':
|
||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
||||
theGPT->SetAttributes(theGPT->GetPartNum());
|
||||
else
|
||||
printf("No partitions\n");
|
||||
break;
|
||||
case 'c': case 'C':
|
||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
|
||||
pn = theGPT->GetPartNum();
|
||||
printf("Enter the partition's new unique GUID:\n");
|
||||
theGPT->SetPartitionGUID(pn, GetGUID());
|
||||
} else printf("No partitions\n");
|
||||
break;
|
||||
case 'd': case 'D':
|
||||
printf("The number of logical sectors per physical sector is %d.\n",
|
||||
theGPT->GetAlignment());
|
||||
break;
|
||||
case 'e': case 'E':
|
||||
printf("Relocating backup data structures to the end of the disk\n");
|
||||
theGPT->MoveSecondHeaderToEnd();
|
||||
break;
|
||||
case 'g': case 'G':
|
||||
printf("Enter the disk's unique GUID:\n");
|
||||
theGPT->SetDiskGUID(GetGUID());
|
||||
break;
|
||||
case 'i': case 'I':
|
||||
theGPT->ShowDetails();
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
temp1 = GetNumber(1, 128, 8, "Enter the number of logical sectors in a physical sector on the\ndisk (1-128, default = 8): ");
|
||||
theGPT->SetAlignment(temp1);
|
||||
break;
|
||||
case 'm': case 'M':
|
||||
MainMenu(filename, theGPT);
|
||||
goOn = 0;
|
||||
break;
|
||||
case 'n': case 'N':
|
||||
theGPT->MakeProtectiveMBR();
|
||||
break;
|
||||
case 'o': case 'O':
|
||||
theGPT->DisplayMBRData();
|
||||
break;
|
||||
case 'p': case 'P':
|
||||
theGPT->DisplayGPTData();
|
||||
break;
|
||||
case 'q': case 'Q':
|
||||
goOn = 0;
|
||||
break;
|
||||
case 'r': case 'R':
|
||||
RecoveryMenu(filename, theGPT);
|
||||
goOn = 0;
|
||||
break;
|
||||
case 's': case 'S':
|
||||
theGPT->ResizePartitionTable();
|
||||
break;
|
||||
case 'v': case 'V':
|
||||
theGPT->Verify();
|
||||
break;
|
||||
case 'w': case 'W':
|
||||
if (theGPT->SaveGPTData() == 1) {
|
||||
goOn = 0;
|
||||
} // if
|
||||
break;
|
||||
case 'z': case 'Z':
|
||||
if (theGPT->DestroyGPT() == 1) {
|
||||
goOn = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ShowExpertCommands();
|
||||
break;
|
||||
} // switch
|
||||
} while (goOn);
|
||||
} // ExpertsMenu()
|
||||
|
||||
void ShowExpertCommands(void) {
|
||||
printf("a\tset attributes\n");
|
||||
printf("c\tchange partition GUID\n");
|
||||
printf("d\tdisplay the number of logical sectors per physical sector\n");
|
||||
printf("e\trelocate backup data structures to the end of the disk\n");
|
||||
printf("g\tchange disk GUID\n");
|
||||
printf("i\tshow detailed information on a partition\n");
|
||||
printf("b\tset the number of logical sectors per physical sector\n");
|
||||
printf("m\treturn to main menu\n");
|
||||
printf("n\tcreate a new protective MBR\n");
|
||||
printf("o\tprint protective MBR data\n");
|
||||
printf("p\tprint the partition table\n");
|
||||
printf("q\tquit without saving changes\n");
|
||||
printf("r\trecovery and transformation options (experts only)\n");
|
||||
printf("s\tresize partition table\n");
|
||||
printf("v\tverify disk\n");
|
||||
printf("w\twrite table to disk and exit\n");
|
||||
printf("z\tzap (destroy) GPT data structures and exit\n");
|
||||
printf("?\tprint this menu\n");
|
||||
} // ShowExpertCommands()
|
||||
*/
|
||||
88
support.cc
88
support.cc
@@ -223,10 +223,10 @@ int GetBlockSize(int fd) {
|
||||
} // if
|
||||
} // if
|
||||
|
||||
if (result != 512) {
|
||||
/* if (result != 512) {
|
||||
printf("\aWARNING! Sector size is not 512 bytes! This program is likely to ");
|
||||
printf("misbehave!\nProceed at your own risk!\n\n");
|
||||
} // if
|
||||
} // if */
|
||||
|
||||
return (result);
|
||||
} // GetBlockSize()
|
||||
@@ -244,9 +244,12 @@ int FindAlignment(int fd) {
|
||||
err = -1;
|
||||
#endif
|
||||
|
||||
if (err < 0) {
|
||||
result = 8;
|
||||
} else {
|
||||
if (err < 0) { // ioctl didn't work; have to guess....
|
||||
if (GetBlockSize(fd) == 512)
|
||||
result = 8; // play it safe; align for 4096-byte sectors
|
||||
else
|
||||
result = 1; // unusual sector size; assume it's the real physical size
|
||||
} else { // ioctl worked; compute alignment
|
||||
result = physicalSectorSize / GetBlockSize(fd);
|
||||
} // if/else
|
||||
return result;
|
||||
@@ -501,7 +504,9 @@ uint64_t disksize(int fd, int *err) {
|
||||
else
|
||||
sectors = (b >> 9);
|
||||
} // if
|
||||
|
||||
// Unintuitively, the above returns values in 512-byte blocks, no
|
||||
// matter what the underlying device's block size. Correct for this....
|
||||
sectors /= (GetBlockSize(fd) / 512);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -517,7 +522,72 @@ uint64_t disksize(int fd, int *err) {
|
||||
sectors = bytes / UINT64_C(512);
|
||||
} // if
|
||||
} // if
|
||||
// sectors = 25000000;
|
||||
// printf("Returning bogus sector size: %d\n", sectors);
|
||||
return sectors;
|
||||
}
|
||||
} // disksize()
|
||||
|
||||
// A variant on the standard read() function. Done to work around
|
||||
// limitations in FreeBSD concerning the matching of the sector
|
||||
// size with the number of bytes read
|
||||
int myRead(int fd, char* buffer, int numBytes) {
|
||||
int blockSize = 512, i, numBlocks, retval;
|
||||
char* tempSpace;
|
||||
|
||||
// Compute required space and allocate memory
|
||||
blockSize = GetBlockSize(fd);
|
||||
if (numBytes <= blockSize) {
|
||||
numBlocks = 1;
|
||||
tempSpace = (char*) malloc(blockSize);
|
||||
} else {
|
||||
numBlocks = numBytes / blockSize;
|
||||
if ((numBytes % blockSize) != 0) numBlocks++;
|
||||
tempSpace = (char*) malloc(numBlocks * blockSize);
|
||||
} // if/else
|
||||
|
||||
// Read the data into temporary space, then copy it to buffer
|
||||
retval = read(fd, tempSpace, numBlocks * blockSize);
|
||||
for (i = 0; i < numBytes; i++) {
|
||||
buffer[i] = tempSpace[i];
|
||||
} // for
|
||||
|
||||
// Adjust the return value, if necessary....
|
||||
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
||||
retval = numBytes;
|
||||
|
||||
free(tempSpace);
|
||||
return retval;
|
||||
} // myRead()
|
||||
|
||||
// A variant on the standard write() function. Done to work around
|
||||
// limitations in FreeBSD concerning the matching of the sector
|
||||
// size with the number of bytes read
|
||||
int myWrite(int fd, char* buffer, int numBytes) {
|
||||
int blockSize = 512, i, numBlocks, retval;
|
||||
char* tempSpace;
|
||||
|
||||
// Compute required space and allocate memory
|
||||
blockSize = GetBlockSize(fd);
|
||||
if (numBytes <= blockSize) {
|
||||
numBlocks = 1;
|
||||
tempSpace = (char*) malloc(blockSize);
|
||||
} else {
|
||||
numBlocks = numBytes / blockSize;
|
||||
if ((numBytes % blockSize) != 0) numBlocks++;
|
||||
tempSpace = (char*) malloc(numBlocks * blockSize);
|
||||
} // if/else
|
||||
|
||||
// Copy the data to my own buffer, then write it
|
||||
for (i = 0; i < numBytes; i++) {
|
||||
tempSpace[i] = buffer[i];
|
||||
} // for
|
||||
for (i = numBytes; i < numBlocks * blockSize; i++) {
|
||||
tempSpace[i] = 0;
|
||||
} // for
|
||||
retval = write(fd, tempSpace, numBlocks * blockSize);
|
||||
|
||||
// Adjust the return value, if necessary....
|
||||
if (((numBlocks * blockSize) != numBytes) && (retval > 0))
|
||||
retval = numBytes;
|
||||
|
||||
free(tempSpace);
|
||||
return retval;
|
||||
} // myRead()
|
||||
|
||||
@@ -68,6 +68,8 @@ int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-en
|
||||
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
|
||||
uint64_t PowerOf2(int value);
|
||||
int OpenForWrite(char* deviceFilename);
|
||||
int myRead(int fd, char* buffer, int numBytes);
|
||||
int myWrite(int fd, char* buffer, int numBytes);
|
||||
void DiskSync(int fd); // resync disk caches to use new partitions
|
||||
|
||||
uint64_t disksize(int fd, int* err);
|
||||
|
||||
Reference in New Issue
Block a user