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:
srs5694
2010-01-05 00:14:19 -05:00
parent 5d58fe0ea1
commit 1e09372bca
10 changed files with 622 additions and 64 deletions

View File

@@ -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. - Fixed bug in display of GUIDs when compiled with some versions of GCC.
- Eliminated warnings caused by additional checks in latest versions of - Eliminated warnings caused by additional checks in latest versions of

View File

@@ -15,6 +15,9 @@ DEPEND= makedepend $(CFLAGS)
gdisk: $(LIB_OBJS) gdisk.o gdisk: $(LIB_OBJS) gdisk.o
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk $(CXX) $(LIB_OBJS) gdisk.o -o gdisk
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -o sgdisk
wipegpt: $(LIB_OBJS) wipegpt.o wipegpt: $(LIB_OBJS) wipegpt.o
$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt $(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt

8
bsd.cc
View File

@@ -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 // Load the BSD disklabel data from an already-opened disk
// file, starting with the specified sector number. // file, starting with the specified sector number.
void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) { 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 i, err, foundSig = 0, bigEnd = 0;
int relative = 0; // assume absolute partition sector numbering int relative = 0; // assume absolute partition sector numbering
uint32_t realSig; uint32_t realSig;
@@ -74,10 +74,10 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
labelFirstLBA = startSector; labelFirstLBA = startSector;
labelLastLBA = endSector; 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) // this buffer. (Done to work around FreeBSD limitation)
lseek64(fd, startSector * 512, SEEK_SET); lseek64(fd, startSector * GetBlockSize(fd), SEEK_SET);
err = read(fd, buffer, 2048); err = read(fd, buffer, 4096);
// Do some strangeness to support big-endian architectures... // Do some strangeness to support big-endian architectures...
bigEnd = (IsLittleEndian() == 0); bigEnd = (IsLittleEndian() == 0);

View File

@@ -4,7 +4,7 @@
// //
// by Rod Smith, project began February 2009 // 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. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
//#include <iostream> //#include <iostream>
@@ -16,7 +16,6 @@
#include "support.h" #include "support.h"
// Function prototypes.... // Function prototypes....
// int ReadPartitions(char* filename, struct GPTData* theGPT);
void MainMenu(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 ExpertsMenu(char* filename, struct GPTData* theGPT);
@@ -29,7 +28,7 @@ int main(int argc, char* argv[]) {
int doMore = 1; int doMore = 1;
char* device = NULL; 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 (argc == 2) { // basic usage
if (SizesOK()) { if (SizesOK()) {

99
gpt.cc
View File

@@ -49,6 +49,7 @@ GPTData::GPTData(void) {
bsdFound = 0; bsdFound = 0;
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
srand((unsigned int) time(NULL)); srand((unsigned int) time(NULL));
mainHeader.numParts = 0;
SetGPTSize(NUM_GPT_ENTRIES); SetGPTSize(NUM_GPT_ENTRIES);
} // GPTData default constructor } // GPTData default constructor
@@ -68,6 +69,7 @@ GPTData::GPTData(char* filename) {
bsdFound = 0; bsdFound = 0;
sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default sectorAlignment = 8; // Align partitions on 4096-byte boundaries by default
srand((unsigned int) time(NULL)); srand((unsigned int) time(NULL));
mainHeader.numParts = 0;
LoadPartitions(filename); LoadPartitions(filename);
} // GPTData(char* filename) constructor } // GPTData(char* filename) constructor
@@ -601,9 +603,9 @@ int GPTData::ForceLoadGPTData(int fd) {
uint32_t newCRC, sizeOfParts; uint32_t newCRC, sizeOfParts;
// Seek to and read the main GPT header // Seek to and read the main GPT header
lseek64(fd, 512, SEEK_SET); lseek64(fd, blockSize, SEEK_SET);
if (read(fd, &mainHeader, 512) != 512) { // read main GPT header if (myRead(fd, (char*) &mainHeader, 512) != 512) { // read main GPT header
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno); fprintf(stderr, "Warning! Error %d reading main GPT header!\n", errno);
} // if } // if
mainCrcOk = CheckHeaderCRC(&mainHeader); mainCrcOk = CheckHeaderCRC(&mainHeader);
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order.... if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
@@ -618,19 +620,19 @@ int GPTData::ForceLoadGPTData(int fd) {
if (mainHeader.backupLBA < diskSize) { if (mainHeader.backupLBA < diskSize) {
seekTo = mainHeader.backupLBA * blockSize; seekTo = mainHeader.backupLBA * blockSize;
} else { } else {
seekTo = (diskSize * blockSize) - UINT64_C(512); seekTo = (diskSize * blockSize) - blockSize;
printf("Warning! Disk size is smaller than the main header indicates! Loading\n" 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" "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" "verify disk integrity, and perhaps options on the experts' menu to repair\n"
"the disk.\n"); "the disk.\n");
} // else } // else
} else { } else {
seekTo = (diskSize * blockSize) - UINT64_C(512); seekTo = (diskSize * blockSize) - blockSize;
} // if/else (mainCrcOk) } // if/else (mainCrcOk)
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) { if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
if (read(fd, &secondHeader, 512) != 512) { // read secondary GPT header if (myRead(fd, (char*) &secondHeader, 512) != 512) { // read secondary GPT header
fprintf(stderr, "Warning! Error %d reading secondary GPT header!", errno); fprintf(stderr, "Warning! Error %d reading secondary GPT header!\n", errno);
} // if } // if
secondCrcOk = CheckHeaderCRC(&secondHeader); secondCrcOk = CheckHeaderCRC(&secondHeader);
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order.... 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)) { if ((lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) && (secondCrcOk)) {
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries; sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
storage = (char*) malloc(sizeOfParts); 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); fprintf(stderr, "Warning! Error %d reading backup partition table!\n", errno);
} // if } // if
newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts); newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
@@ -716,7 +718,7 @@ int GPTData::LoadMainTable(void) {
// matches the stored value // matches the stored value
lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET); lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET);
sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries; 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); fprintf(stderr, "Warning! Error %d when loading the main partition table!\n", errno);
} // if } // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
@@ -740,7 +742,7 @@ void GPTData::LoadSecondTableAsMain(void) {
if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) { if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
SetGPTSize(secondHeader.numParts); SetGPTSize(secondHeader.numParts);
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries; 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); fprintf(stderr, "Warning! Read error %d! Misbehavior now likely!\n", errno);
} // if } // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts); newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
@@ -852,15 +854,21 @@ int GPTData::SaveGPTData(void) {
protectiveMBR.WriteMBRData(fd); protectiveMBR.WriteMBRData(fd);
// Now write the main GPT header... // Now write the main GPT header...
if (allOK) if (allOK) {
if (write(fd, &mainHeader, 512) == -1) if (lseek64(fd, blockSize, SEEK_SET) != (off_t) -1) {
allOK = 0; if (myWrite(fd, (char*) &mainHeader, 512) == -1)
allOK = 0;
} else allOK = 0; // if (lseek64()...)
} // if (allOK)
// Now write the main partition tables... // Now write the main partition tables...
if (allOK) { 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; allOK = 0;
} // if } else allOK = 0; // if (lseek64()...)
} // if (allOK)
// Now seek to near the end to write the secondary GPT.... // Now seek to near the end to write the secondary GPT....
if (allOK) { if (allOK) {
@@ -872,14 +880,19 @@ int GPTData::SaveGPTData(void) {
} // if } // if
// Now write the secondary partition tables.... // Now write the secondary partition tables....
if (allOK) if (allOK) {
if (write(fd, partitions, GPT_SIZE * numParts) == -1) if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
allOK = 0; allOK = 0;
} // if (allOK)
// Now write the secondary GPT header... // Now write the secondary GPT header...
if (allOK) if (allOK) {
if (write(fd, &secondHeader, 512) == -1) offset = mainHeader.backupLBA * blockSize;
allOK = 0; 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 // re-read the partition table
if (allOK) { if (allOK) {
@@ -944,17 +957,17 @@ int GPTData::SaveGPTBackup(char* filename) {
// Now write the main GPT header... // Now write the main GPT header...
if (allOK) if (allOK)
if (write(fd, &mainHeader, 512) == -1) if (myWrite(fd, (char*) &mainHeader, 512) == -1)
allOK = 0; allOK = 0;
// Now write the secondary GPT header... // Now write the secondary GPT header...
if (allOK) if (allOK)
if (write(fd, &secondHeader, 512) == -1) if (myWrite(fd, (char*) &secondHeader, 512) == -1)
allOK = 0; allOK = 0;
// Now write the main partition tables... // Now write the main partition tables...
if (allOK) { if (allOK) {
if (write(fd, partitions, GPT_SIZE * numParts) == -1) if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
allOK = 0; allOK = 0;
} // if } // if
@@ -997,7 +1010,7 @@ int GPTData::LoadGPTBackup(char* filename) {
// Load the main GPT header, check its vaility, and set the GPT // Load the main GPT header, check its vaility, and set the GPT
// size based on the data // 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); fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if } // if
mainCrcOk = CheckHeaderCRC(&mainHeader); 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 // Load the backup GPT header in much the same way as the main
// GPT header.... // 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); fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if } // if
secondCrcOk = CheckHeaderCRC(&secondHeader); secondCrcOk = CheckHeaderCRC(&secondHeader);
@@ -1045,7 +1058,7 @@ int GPTData::LoadGPTBackup(char* filename) {
// Load main partition table, and record whether its CRC // Load main partition table, and record whether its CRC
// matches the stored value // matches the stored value
sizeOfParts = numParts * sizeOfEntries; 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); fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if } // if
@@ -1109,6 +1122,7 @@ void GPTData::DisplayGPTData(void) {
BytesToSI(diskSize * blockSize, sizeInSI); BytesToSI(diskSize * blockSize, sizeInSI);
printf("Disk %s: %llu sectors, %s\n", device, printf("Disk %s: %llu sectors, %s\n", device,
(unsigned long long) diskSize, sizeInSI); (unsigned long long) diskSize, sizeInSI);
printf("Logical sector size: %d bytes\n", blockSize);
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 %llu, last usable sector is %llu\n", 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 // If prompt == 0, don't ask user about proceeding and do NOT wipe out
// MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.) // MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.)
int GPTData::DestroyGPT(int prompt) { int GPTData::DestroyGPT(int prompt) {
int fd, i, sum; int fd, i, sum, tableSize;
char blankSector[512], goOn = 'Y', blank = 'N'; char blankSector[512], goOn = 'Y', blank = 'N';
char* emptyTable;
for (i = 0; i < 512; i++) { for (i = 0; i < 512; i++) {
blankSector[i] = '\0'; blankSector[i] = '\0';
@@ -1326,24 +1341,24 @@ int GPTData::DestroyGPT(int prompt) {
} // if } // if
#endif #endif
if (fd != -1) { if (fd != -1) {
lseek64(fd, mainHeader.currentLBA * 512, SEEK_SET); // seek to GPT header lseek64(fd, mainHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
if (write(fd, blankSector, 512) != 512) { // blank it out if (myWrite(fd, blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! GPT main header not overwritten! Error is %d\n", errno); fprintf(stderr, "Warning! GPT main header not overwritten! Error is %d\n", errno);
} // if } // if
lseek64(fd, mainHeader.partitionEntriesLBA * 512, SEEK_SET); // seek to partition table lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
sum = 0; tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
for (i = 0; i < GetBlocksInPartTable(); i++) emptyTable = (char*) malloc(tableSize);
sum += write(fd, blankSector, 512); for (i = 0; i < tableSize; i++)
if (sum != 512 * GetBlocksInPartTable()) 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); 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 lseek64(fd, secondHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
sum = 0; sum = myWrite(fd, emptyTable, tableSize);
for (i = 0; i < GetBlocksInPartTable(); i++) if (sum != tableSize)
sum += write(fd, blankSector, 512);
if (sum != 512 * GetBlocksInPartTable())
fprintf(stderr, "Warning! GPT backup partition table not overwritten! Error is %d\n", errno); 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 lseek64(fd, secondHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
if (write(fd, blankSector, 512) != 512) { // blank it out if (myWrite(fd, blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno); fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
} // if } // if
if (prompt) { if (prompt) {
@@ -1357,7 +1372,7 @@ int GPTData::DestroyGPT(int prompt) {
// structures). // structures).
if (blank == 'Y') { if (blank == 'Y') {
lseek64(fd, 0, SEEK_SET); 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); fprintf(stderr, "Warning! MBR not overwritten! Error is %d!\n", errno);
} // if } // if
} else { } else {

2
gpt.h
View File

@@ -145,8 +145,6 @@ public:
uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;} uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}
uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;} uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;} uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
mainHeader.sizeOfPartitionEntries) / blockSize;}
uint32_t CountParts(void); uint32_t CountParts(void);
int GetAlignment(void) {return sectorAlignment;} int GetAlignment(void) {return sectorAlignment;}

6
mbr.cc
View File

@@ -98,7 +98,7 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
EmptyMBR(0); EmptyMBR(0);
err = lseek64(fd, 0, SEEK_SET); err = lseek64(fd, 0, SEEK_SET);
err = read(fd, &tempMBR, 512); err = myRead(fd, (char*) &tempMBR, 512);
for (i = 0; i < 440; i++) for (i = 0; i < 440; i++)
code[i] = tempMBR.code[i]; code[i] = tempMBR.code[i];
diskSignature = tempMBR.diskSignature; 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); fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
partNum = -1; 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", fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
(unsigned long) offset); (unsigned long) offset);
partNum = -1; partNum = -1;
@@ -289,7 +289,7 @@ void MBRData::WriteMBRData(int fd) {
// Now write that data structure... // Now write that data structure...
lseek64(fd, 0, SEEK_SET); 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); fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
} // if } // if

464
sgdisk.cc Normal file
View 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()
*/

View File

@@ -223,10 +223,10 @@ int GetBlockSize(int fd) {
} // if } // if
} // if } // if
if (result != 512) { /* if (result != 512) {
printf("\aWARNING! Sector size is not 512 bytes! This program is likely to "); printf("\aWARNING! Sector size is not 512 bytes! This program is likely to ");
printf("misbehave!\nProceed at your own risk!\n\n"); printf("misbehave!\nProceed at your own risk!\n\n");
} // if } // if */
return (result); return (result);
} // GetBlockSize() } // GetBlockSize()
@@ -244,9 +244,12 @@ int FindAlignment(int fd) {
err = -1; err = -1;
#endif #endif
if (err < 0) { if (err < 0) { // ioctl didn't work; have to guess....
result = 8; if (GetBlockSize(fd) == 512)
} else { 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); result = physicalSectorSize / GetBlockSize(fd);
} // if/else } // if/else
return result; return result;
@@ -501,7 +504,9 @@ uint64_t disksize(int fd, int *err) {
else else
sectors = (b >> 9); sectors = (b >> 9);
} // if } // 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
#endif #endif
@@ -517,7 +522,72 @@ uint64_t disksize(int fd, int *err) {
sectors = bytes / UINT64_C(512); sectors = bytes / UINT64_C(512);
} // if } // if
} // if } // if
// sectors = 25000000;
// printf("Returning bogus sector size: %d\n", sectors);
return 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()

View File

@@ -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 void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
uint64_t PowerOf2(int value); uint64_t PowerOf2(int value);
int OpenForWrite(char* deviceFilename); 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 void DiskSync(int fd); // resync disk caches to use new partitions
uint64_t disksize(int fd, int* err); uint64_t disksize(int fd, int* err);