summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsrs5694 <srs5694@users.sourceforge.net>2010-01-26 16:00:26 -0500
committersrs5694 <srs5694@users.sourceforge.net>2010-01-26 16:00:26 -0500
commit546a9c7c369df465021feecb20f6a8f81b6df6bc (patch)
tree280a7cd1fda2a5614582f8675e415d4043fe5e93
parentadd79a6e1b3a1af1305f02d51eb3aa148f580caa (diff)
downloadsgdisk-546a9c7c369df465021feecb20f6a8f81b6df6bc.tar.gz
New files to support disk I/O restructuring and (currently broken)
Windows version.
-rw-r--r--CHANGELOG35
-rw-r--r--Makefile2
-rw-r--r--bsd.cc33
-rw-r--r--bsd.h16
-rw-r--r--crc32.cc5
-rw-r--r--gdisk.cc5
-rw-r--r--gpt.cc338
-rw-r--r--gpt.h11
-rw-r--r--gptpart.cc41
-rw-r--r--gptpart.h6
-rw-r--r--mbr.cc215
-rw-r--r--mbr.h13
-rw-r--r--support.cc290
-rw-r--r--support.h18
14 files changed, 428 insertions, 600 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5e81852..c09020a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,33 @@
-0.6.1 (1/20/2009):
+0.6.2 (?/??/2010):
+------------------
+
+- Enabled default partition type code of 0700 when creating partitions
+ or changing their type codes. (Type 0700, Linux/Windows data, is set if
+ the user hits the Enter key alone.)
+
+- Fixed bug in sort ('s' on main menu) option that caused partition
+ numbers to begin at more than 1 if the original partition list had
+ too many empty partitions before the last one defined.
+
+- Improved code to determine which partition table to load in case of
+ CRC mismatches between the partition tables and the stored CRC values
+ in the headers.
+
+- Compiles using MinGW (http://www.mingw.org) to create a Windows binary.
+ The resulting Windows program is flaky and can't write to the disk,
+ though, so I'm not creating an official Windows release just yet (and
+ maybe never will).
+
+- Moved all disk I/O functions to the new DiskIO class. This helps with the
+ Windows port; it uses diskio-windows.cc for Windows-specific code,
+ diskio-unix.cc for the Linux, FreeBSD, and OS X code, and diskio.cc for
+ cross-platform disk I/O code.
+
+- Changed BSD disklabel detection code to be more correct (I think).
+ This change has no effect on my test disks, but I hope it'll work
+ better on disks with sector sizes other than 512 or 2048.
+
+0.6.1 (1/20/2010):
------------------
- Fixed bug that returned incorrect disk size on 32-bit versions of
@@ -9,7 +38,7 @@
- Fixed bug that caused BSD disklabel conversion to fail.
-0.6.0 (1/15/2009):
+0.6.0 (1/15/2010):
------------------
- Fixed bug that caused the convert to MBR function to fail.
@@ -22,7 +51,7 @@
"+128M") to be misinterpreted as from the start of the range rather than
from the default value.
-0.5.3 (1/4/2009):
+0.5.3 (1/4/2010):
-----------------
- Fixed bug in display of GUIDs when compiled with some versions of GCC.
diff --git a/Makefile b/Makefile
index 2834ecb..52ce8ef 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ CC=gcc
CXX=g++
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
-LIB_NAMES=crc32 support gptpart mbr gpt bsd parttypes attributes
+LIB_NAMES=crc32 support gptpart mbr gpt bsd parttypes attributes diskio diskio-unix
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
diff --git a/bsd.cc b/bsd.cc
index e1b3907..7052001 100644
--- a/bsd.cc
+++ b/bsd.cc
@@ -43,26 +43,35 @@ BSDData::~BSDData(void) {
// just opens the device file and then calls an overloaded function to do
// the bulk of the work.
int BSDData::ReadBSDData(char* device, uint64_t startSector, uint64_t endSector) {
- int fd, allOK = 1;
+ int allOK = 1, tempMyDisk = 0;
if (device != NULL) {
- if ((fd = open(device, O_RDONLY)) != -1) {
- ReadBSDData(fd, startSector, endSector);
+ if (myDisk == NULL) {
+ myDisk = new DiskIO;
+ tempMyDisk = 1;
+ } // if
+ if (myDisk->OpenForRead(device)) {
+ ReadBSDData(myDisk, startSector, endSector);
} else {
allOK = 0;
} // if/else
- close(fd);
+ myDisk->Close();
} else {
allOK = 0;
} // if/else
+ if (tempMyDisk) {
+ delete myDisk;
+ myDisk = NULL;
+ } // if
+
return allOK;
} // BSDData::ReadBSDData() (device filename version)
// 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) {
+void BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSector) {
uint8_t buffer[4096]; // I/O buffer
int i, err, foundSig = 0, bigEnd = 0;
int relative = 0; // assume absolute partition sector numbering
@@ -70,17 +79,19 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
uint32_t* temp32;
uint16_t* temp16;
BSDRecord* tempRecords;
- int offset[3] = { LABEL_OFFSET1, LABEL_OFFSET2, LABEL_OFFSET3 };
+ int offset[NUM_OFFSETS] = { LABEL_OFFSET1, LABEL_OFFSET2 };
+ myDisk = theDisk;
labelFirstLBA = startSector;
labelLastLBA = endSector;
+ offset[1] = myDisk->GetBlockSize();
// Read 4096 bytes (eight 512-byte sectors or equivalent)
// into memory; we'll extract data from this buffer.
// (Done to work around FreeBSD limitation on size of reads
// from block devices.)
- lseek64(fd, startSector * GetBlockSize(fd), SEEK_SET);
- err = read(fd, buffer, 4096);
+ myDisk->Seek(startSector /* * myDisk->GetBlockSize() */);
+ myDisk->Read(buffer, 4096);
// Do some strangeness to support big-endian architectures...
bigEnd = (IsLittleEndian() == 0);
@@ -88,7 +99,7 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
if (bigEnd)
ReverseBytes(&realSig, 4);
- // Look for the signature at any of three locations.
+ // Look for the signature at any of two locations.
// Note that the signature is repeated at both the original
// offset and 132 bytes later, so we need two checks....
i = 0;
@@ -104,7 +115,7 @@ void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
} // if found signature
} // if/else
i++;
- } while ((!foundSig) && (i < 3));
+ } while ((!foundSig) && (i < NUM_OFFSETS));
// Load partition metadata from the buffer....
temp32 = (uint32_t*) &buffer[labelStart + 40];
@@ -307,7 +318,7 @@ GPTPart BSDData::AsGPT(int i) {
guid.SetType(0x0700); break;
} // switch
// Set the partition name to the name of the type code....
- guid.SetName((unsigned char*) guid.GetNameType(tempStr));
+ guid.SetName((unsigned char*) guid.GetNameType().c_str());
} // if
return guid;
} // BSDData::AsGPT()
diff --git a/bsd.h b/bsd.h
index e7fbfc7..77d3d3c 100644
--- a/bsd.h
+++ b/bsd.h
@@ -5,17 +5,22 @@
#include <stdint.h>
#include <sys/types.h>
-#include <sys/ioctl.h>
#include "gptpart.h"
+#include "diskio.h"
#ifndef __BSD_STRUCTS
#define __BSD_STRUCTS
#define BSD_SIGNATURE UINT32_C(0x82564557) /* BSD disklabel signature ("magic") */
-#define LABEL_OFFSET1 64 /* BSD disklabels can start at any of these three */
-#define LABEL_OFFSET2 512 /* values; check all for valid signatures */
-#define LABEL_OFFSET3 2048
+// BSD disklabels can start at offsets of 64 or the sector size -- at least,
+// I *THINK* that's what's going on. I've seen them at 64 or 512 on disks
+// with 512-byte blocks and at 2048 on disks with 2048-byte blocks. The
+// LABEL_OFFSET2 value will be replaced by the block size in the
+// ReadBSDData() function....
+#define LABEL_OFFSET1 64
+#define LABEL_OFFSET2 512
+#define NUM_OFFSETS 2
// FreeBSD documents a maximum # of partitions of 8, but I saw 16 on a NetBSD
// disk. I'm quadrupling that for further safety. Note that BSDReadData()
@@ -64,11 +69,12 @@ class BSDData {
uint64_t labelLastLBA; // final sector of BSD disklabel
uint64_t labelStart; // BSD disklabel start point in bytes from labelFirstLBA
BSDValidity state;
+ DiskIO *myDisk;
public:
BSDData(void);
~BSDData(void);
int ReadBSDData(char* deviceFilename, uint64_t startSector, uint64_t endSector);
- void ReadBSDData(int fd, uint64_t startSector, uint64_t endSector);
+ void ReadBSDData(DiskIO *myDisk, uint64_t startSector, uint64_t endSector);
void ReverseMetaBytes(void);
void DisplayBSDData(void);
int ShowState(void); // returns 1 if BSD disklabel detected
diff --git a/crc32.cc b/crc32.cc
index 2b9ee9a..d253dd9 100644
--- a/crc32.cc
+++ b/crc32.cc
@@ -16,19 +16,20 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
+#include "crc32.h"
/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
* so make sure, you call it before using the other
* functions!
*/
-u_int32_t crc_tab[256];
+uint32_t crc_tab[256];
/* chksum_crc() -- to a given block, this one calculates the
* crc32-checksum until the length is
* reached. the crc32-checksum will be
* the result.
*/
-u_int32_t chksum_crc32 (unsigned char *block, unsigned int length)
+uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
{
register unsigned long crc;
unsigned long i;
diff --git a/gdisk.cc b/gdisk.cc
index ef3beb1..0809c3c 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -121,10 +121,7 @@ void MainMenu(char* filename, struct GPTData* theGPT) {
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
+ theGPT->Verify();
break;
case 'w': case 'W':
if (theGPT->SaveGPTData() == 1)
diff --git a/gpt.cc b/gpt.cc
index 39c570e..867c3ff 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -24,6 +24,7 @@
#include "support.h"
#include "parttypes.h"
#include "attributes.h"
+#include "diskio.h"
using namespace std;
@@ -102,25 +103,29 @@ int GPTData::Verify(void) {
if (!mainCrcOk) {
problems++;
printf("\nProblem: The CRC for the main GPT header is invalid. The main GPT header may\n"
- "be corrupt. Consider loading the backup GPT header to rebuild the main GPT\n"
- "header\n");
+ "be corrupt. Consider loading the backup GPT header to rebuild the main GPT\n"
+ "header ('b' on the recovery & transformation menu). This report may be a false\n"
+ "alarm if you've already corrected other problems.\n");
} // if
if (!mainPartsCrcOk) {
problems++;
printf("\nProblem: The CRC for the main partition table is invalid. This table may be\n"
- "corrupt. Consider loading the backup partition table.\n");
+ "corrupt. Consider loading the backup partition table ('c' on the recovery &\n"
+ "transformation menu). This report may be a false alarm if you've already\n"
+ "corrected other problems.\n");
} // if
if (!secondCrcOk) {
problems++;
printf("\nProblem: The CRC for the backup GPT header is invalid. The backup GPT header\n"
"may be corrupt. Consider using the main GPT header to rebuild the backup GPT\n"
- "header.\n");
+ "header ('d' on the recovery & transformation menu). This report may be a false\n"
+ "alarm if you've already corrected other problems.\n");
} // if
if (!secondPartsCrcOk) {
problems++;
printf("\nCaution: The CRC for the backup partition table is invalid. This table may\n"
- "be corrupt. This program will automatically create a new backup partition\n"
- "table when you save your partitions.\n");
+ "be corrupt. This program will automatically create a new backup partition\n"
+ "table when you save your partitions.\n");
} // if
// Now check that the main and backup headers both point to themselves....
@@ -143,30 +148,32 @@ int GPTData::Verify(void) {
if (mainHeader.currentLBA != secondHeader.backupLBA) {
problems++;
printf("\nProblem: main GPT header's current LBA pointer (%llu) doesn't\n"
- "match the backup GPT header's LBA pointer(%llu)\n",
+ "match the backup GPT header's LBA pointer(%llu).\n",
(unsigned long long) mainHeader.currentLBA,
(unsigned long long) secondHeader.backupLBA);
} // if
if (mainHeader.backupLBA != secondHeader.currentLBA) {
problems++;
printf("\nProblem: main GPT header's backup LBA pointer (%llu) doesn't\n"
- "match the backup GPT header's current LBA pointer (%llu)\n",
- (unsigned long long) mainHeader.backupLBA,
+ "match the backup GPT header's current LBA pointer (%llu).\n"
+ "The 'e' option on the experts' menu may fix this problem.\n",
+ (unsigned long long) mainHeader.backupLBA,
(unsigned long long) secondHeader.currentLBA);
} // if
if (mainHeader.firstUsableLBA != secondHeader.firstUsableLBA) {
problems++;
printf("\nProblem: main GPT header's first usable LBA pointer (%llu) doesn't\n"
- "match the backup GPT header's first usable LBA pointer (%llu)\n",
- (unsigned long long) mainHeader.firstUsableLBA,
+ "match the backup GPT header's first usable LBA pointer (%llu)\n",
+ (unsigned long long) mainHeader.firstUsableLBA,
(unsigned long long) secondHeader.firstUsableLBA);
} // if
if (mainHeader.lastUsableLBA != secondHeader.lastUsableLBA) {
problems++;
printf("\nProblem: main GPT header's last usable LBA pointer (%llu) doesn't\n"
- "match the backup GPT header's last usable LBA pointer (%llu)\n",
- (unsigned long long) mainHeader.lastUsableLBA,
+ "match the backup GPT header's last usable LBA pointer (%llu)\n",
+ (unsigned long long) mainHeader.lastUsableLBA,
(unsigned long long) secondHeader.lastUsableLBA);
+ printf("The 'e' option on the experts' menu can probably fix this problem.\n");
} // if
if ((mainHeader.diskGUID.data1 != secondHeader.diskGUID.data1) ||
(mainHeader.diskGUID.data2 != secondHeader.diskGUID.data2)) {
@@ -175,6 +182,8 @@ int GPTData::Verify(void) {
GUIDToStr(mainHeader.diskGUID, tempStr));
printf("match the backup GPT header's disk GUID (%s)\n",
GUIDToStr(secondHeader.diskGUID, tempStr));
+ printf("You should use the 'b' or 'd' option on the recovery & transformation menu to\n"
+ "select one or the other header.\n");
} // if
if (mainHeader.numParts != secondHeader.numParts) {
problems++;
@@ -182,6 +191,7 @@ int GPTData::Verify(void) {
"match the backup GPT header's number of partitions (%lu)\n",
(unsigned long) mainHeader.numParts,
(unsigned long) secondHeader.numParts);
+ printf("Resizing the partition table ('s' on the experts' menu) may help.\n");
} // if
if (mainHeader.sizeOfPartitionEntries != secondHeader.sizeOfPartitionEntries) {
problems++;
@@ -189,6 +199,8 @@ int GPTData::Verify(void) {
"match the backup GPT header's size of partition entries (%lu)\n",
(unsigned long) mainHeader.sizeOfPartitionEntries,
(unsigned long) secondHeader.sizeOfPartitionEntries);
+ printf("You should use the 'b' or 'd' option on the recovery & transformation menu to\n"
+ "select one or the other header.\n");
} // if
// Now check for a few other miscellaneous problems...
@@ -197,8 +209,9 @@ int GPTData::Verify(void) {
problems++;
printf("\nProblem: Disk is too small to hold all the data!\n");
printf("(Disk size is %llu sectors, needs to be %llu sectors.)\n",
- (unsigned long long) diskSize,
- (unsigned long long) mainHeader.backupLBA);
+ (unsigned long long) diskSize,
+ (unsigned long long) mainHeader.backupLBA);
+ printf("The 'e' option on the experts' menu may fix this problem.\n");
} // if
// Check for overlapping partitions....
@@ -226,11 +239,10 @@ int GPTData::Verify(void) {
totalFree = FindFreeBlocks(&numSegments, &largestSegment);
BytesToSI(totalFree * (uint64_t) blockSize, siTotal);
BytesToSI(largestSegment * (uint64_t) blockSize, siLargest);
- printf("No problems found. %llu free sectors (%s) available in %u\n"
- "segments, the largest of which is %llu sectors (%s) in size\n",
- (unsigned long long) totalFree,
- siTotal, numSegments, (unsigned long long) largestSegment,
- siLargest);
+ printf("No problems found. %llu free sectors ", (unsigned long long) totalFree);
+ printf("(%s) available in %u\n", siTotal, numSegments);
+ printf("segments, the largest of which is %llu sectors ", (unsigned long long) largestSegment);
+ printf("(%s) in size\n", siLargest);
} else {
printf("\nIdentified %d problems!\n", problems);
} // if/else
@@ -276,7 +288,7 @@ int GPTData::CheckGPTSize(void) {
} // Problem at start of disk
if (mainHeader.lastUsableLBA < lastUsedBlock) {
overlap = lastUsedBlock - mainHeader.lastUsableLBA;
- printf("Warning! Secondary partition table overlaps the last partition by %lu blocks\n",
+ printf("Warning! Secondary partition table overlaps the last partition by %lu blocks!\n",
(unsigned long) overlap);
if (lastUsedBlock > (diskSize - 2)) {
printf("You will need to delete this partition or resize it in another utility.\n");
@@ -415,6 +427,7 @@ void GPTData::RebuildMainHeader(void) {
mainHeader.partitionEntriesCRC = secondHeader.partitionEntriesCRC;
for (i = 0 ; i < GPT_RESERVED; i++)
mainHeader.reserved2[i] = secondHeader.reserved2[i];
+ mainCrcOk = secondCrcOk;
} // GPTData::RebuildMainHeader()
// Rebuild the secondary GPT header, using the main header as a model.
@@ -438,6 +451,7 @@ void GPTData::RebuildSecondHeader(void) {
secondHeader.partitionEntriesCRC = mainHeader.partitionEntriesCRC;
for (i = 0 ; i < GPT_RESERVED; i++)
secondHeader.reserved2[i] = mainHeader.reserved2[i];
+ secondCrcOk = mainCrcOk;
} // GPTData::RebuildSecondHeader()
// Search for hybrid MBR entries that have no corresponding GPT partition.
@@ -502,15 +516,15 @@ int GPTData::FindOverlaps(void) {
// protective MBR) and loads BSD disklabel data (which is probably invalid).
// It also looks for APM data, forces a load of GPT data, and summarizes
// the results.
-void GPTData::PartitionScan(int fd) {
+void GPTData::PartitionScan(void) {
BSDData bsdDisklabel;
// Read the MBR & check for BSD disklabel
- protectiveMBR.ReadMBRData(fd);
- bsdDisklabel.ReadBSDData(fd, 0, diskSize - 1);
+ protectiveMBR.ReadMBRData(&myDisk);
+ bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1);
// Load the GPT data, whether or not it's valid
- ForceLoadGPTData(fd);
+ ForceLoadGPTData();
if (!beQuiet) {
printf("Partition table scan:\n");
@@ -539,7 +553,7 @@ int GPTData::LoadPartitions(char* deviceFilename) {
BSDData bsdDisklabel;
// First, do a test to see if writing will be possible later....
- fd = OpenForWrite(deviceFilename);
+ fd = myDisk.OpenForWrite(deviceFilename);
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",
@@ -552,15 +566,16 @@ int GPTData::LoadPartitions(char* deviceFilename) {
printf("\n");
justLooking = 1;
} // if
- close(fd);
+ myDisk.Close();
- if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
+// if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
+ if (myDisk.OpenForRead(deviceFilename)) {
// store disk information....
- diskSize = disksize(fd, &err);
- blockSize = (uint32_t) GetBlockSize(fd);
- sectorAlignment = FindAlignment(fd);
+ diskSize = myDisk.DiskSize(&err);
+ blockSize = (uint32_t) myDisk.GetBlockSize();
+ sectorAlignment = myDisk.FindAlignment();
strcpy(device, deviceFilename);
- PartitionScan(fd); // Check for partition types, load GPT, & print summary
+ PartitionScan(); // Check for partition types, load GPT, & print summary
whichWasUsed = UseWhichPartitions();
switch (whichWasUsed) {
@@ -568,7 +583,7 @@ int GPTData::LoadPartitions(char* deviceFilename) {
XFormPartitions();
break;
case use_bsd:
- bsdDisklabel.ReadBSDData(fd, 0, diskSize - 1);
+ bsdDisklabel.ReadBSDData(&myDisk, 0, diskSize - 1);
// bsdDisklabel.DisplayBSDData();
ClearGPTData();
protectiveMBR.MakeProtectiveMBR(1); // clear boot area (option 1)
@@ -612,17 +627,18 @@ int GPTData::LoadPartitions(char* deviceFilename) {
// Loads the GPT, as much as possible. Returns 1 if this seems to have
// succeeded, 0 if there are obvious problems....
-int GPTData::ForceLoadGPTData(int fd) {
+int GPTData::ForceLoadGPTData(void) {
int allOK = 1, validHeaders;
off_t seekTo;
char* storage;
uint32_t newCRC, sizeOfParts;
// Seek to and read the main GPT header
- 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
+ if (myDisk.Seek(1)) {
+ if (myDisk.Read(&mainHeader, 512) != 512) { // read main GPT header
+ fprintf(stderr, "Warning! Error %d reading main GPT header!\n", errno);
+ } // if read not OK
+ } else allOK = 0; // if/else seek OK
mainCrcOk = CheckHeaderCRC(&mainHeader);
if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
ReverseHeaderBytes(&mainHeader);
@@ -634,20 +650,20 @@ int GPTData::ForceLoadGPTData(int fd) {
// disk instead.
if (mainCrcOk) {
if (mainHeader.backupLBA < diskSize) {
- seekTo = mainHeader.backupLBA * blockSize;
+ seekTo = mainHeader.backupLBA;
} else {
- seekTo = (diskSize * blockSize) - blockSize;
+ seekTo = diskSize - UINT64_C(1);
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) - blockSize;
+ seekTo = diskSize - UINT64_C(1);
} // if/else (mainCrcOk)
- if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
- if (myRead(fd, (char*) &secondHeader, 512) != 512) { // read secondary GPT header
+ if (myDisk.Seek(seekTo)) {
+ if (myDisk.Read(&secondHeader, 512) != 512) { // read secondary GPT header
fprintf(stderr, "Warning! Error %d reading secondary GPT header!\n", errno);
} // if
secondCrcOk = CheckHeaderCRC(&secondHeader);
@@ -675,31 +691,46 @@ int GPTData::ForceLoadGPTData(int fd) {
// We're calling the GPT valid, but there's a possibility that one
// of the two headers is corrupt. If so, use the one that seems to
// be in better shape to regenerate the bad one
- if (validHeaders == 2) { // valid backup header, invalid main header
- printf("Caution: invalid main GPT header, but valid backup; regenerating main header\n"
- "from backup!\n");
- RebuildMainHeader();
- mainCrcOk = secondCrcOk; // Since copied, use CRC validity of backup
- } else if (validHeaders == 1) { // valid main header, invalid backup
- printf("Caution: invalid backup GPT header, but valid main header; regenerating\n"
- "backup header from main header.\n");
+ if (validHeaders == 1) { // valid main header, invalid backup header
+ fprintf(stderr, "\aCaution: invalid backup GPT header, but valid main header; regenerating\n"
+ "backup header from main header.\n\n");
RebuildSecondHeader();
+ state = gpt_corrupt;
secondCrcOk = mainCrcOk; // Since regenerated, use CRC validity of main
+ } else if (validHeaders == 2) { // valid backup header, invalid main header
+ fprintf(stderr, "\aCaution: invalid main GPT header, but valid backup; regenerating main header\n"
+ "from backup!\n\n");
+ RebuildMainHeader();
+ state = gpt_corrupt;
+ mainCrcOk = secondCrcOk; // Since copied, use CRC validity of backup
} // if/else/if
- // Load the main partition table, including storing results of its
- // CRC check
- if (LoadMainTable() == 0)
- allOK = 0;
+ // Figure out which partition table to load....
+ // Load the main partition table, since either its header's CRC is OK or the
+ // backup header's CRC is not OK....
+ if (mainCrcOk || !secondCrcOk) {
+ if (LoadMainTable() == 0)
+ allOK = 0;
+ } else { // bad main header CRC and backup header CRC is OK
+ state = gpt_corrupt;
+ if (LoadSecondTableAsMain()) {
+ fprintf(stderr, "\aWarning: Invalid CRC on main header data; loaded backup partition table.\n");
+ } else { // backup table bad, bad main header CRC, but try main table in desperation....
+ if (LoadMainTable() == 0) {
+ allOK = 0;
+ fprintf(stderr, "\a\aWarning! Unable to load either main or backup partition table!\n");
+ } // if
+ } // if/else (LoadSecondTableAsMain())
+ } // if/else (load partition table)
// Load backup partition table into temporary storage to check
// its CRC and store the results, then discard this temporary
// storage, since we don't use it in any but recovery operations
- seekTo = secondHeader.partitionEntriesLBA * (off_t) blockSize;
- if ((lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) && (secondCrcOk)) {
+ seekTo = secondHeader.partitionEntriesLBA;
+ if ((myDisk.Seek(seekTo)) && (secondCrcOk)) {
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
storage = (char*) malloc(sizeOfParts);
- if (myRead(fd, storage, sizeOfParts) != sizeOfParts) {
+ if (myDisk.Read(storage, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Error %d reading backup partition table!\n", errno);
} // if
newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
@@ -707,10 +738,18 @@ int GPTData::ForceLoadGPTData(int fd) {
secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
} // if
+ // Problem with main partition table; if backup is OK, use it instead....
+ if (secondPartsCrcOk && secondCrcOk && !mainPartsCrcOk) {
+ state = gpt_corrupt;
+ allOK = allOK && LoadSecondTableAsMain();
+ fprintf(stderr, "\aWarning! Main partition table CRC mismatch! Loaded backup "
+ "partition table\ninstead of main partition table!\n\n");
+ } // if
+
// Check for valid CRCs and warn if there are problems
if ((mainCrcOk == 0) || (secondCrcOk == 0) || (mainPartsCrcOk == 0) ||
(secondPartsCrcOk == 0)) {
- printf("Warning! One or more CRCs don't match. You should repair the disk!\n");
+ printf("Warning! One or more CRCs don't match. You should repair the disk!\n\n");
state = gpt_corrupt;
} // if
} else {
@@ -722,44 +761,50 @@ int GPTData::ForceLoadGPTData(int fd) {
// Loads the partition table pointed to by the main GPT header. The
// main GPT header in memory MUST be valid for this call to do anything
// sensible!
+// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
int GPTData::LoadMainTable(void) {
- int fd, retval = 0;
+ int fd, retval = 1;
uint32_t newCRC, sizeOfParts;
- if ((fd = open(device, O_RDONLY)) != -1) {
+ if (myDisk.OpenForRead(device)) {
// Set internal data structures for number of partitions on the disk
SetGPTSize(mainHeader.numParts);
// Load main partition table, and record whether its CRC
// matches the stored value
- lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET);
+ if (!myDisk.Seek(mainHeader.partitionEntriesLBA))
+ retval = 0;
sizeOfParts = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
- if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
+ if (myDisk.Read(partitions, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Error %d when loading the main partition table!\n", errno);
+ retval = 0;
} // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
if (IsLittleEndian() == 0)
ReversePartitionBytes();
- retval = 1;
- } // if
+ } else retval = 0; // if open for read....
return retval;
} // GPTData::LoadMainTable()
// Load the second (backup) partition table as the primary partition
-// table. Used in repair functions
-void GPTData::LoadSecondTableAsMain(void) {
- int fd;
- off_t seekTo;
+// table. Used in repair functions, and when starting up if the main
+// partition table is damaged.
+// Returns 1 on success, 0 on failure. CRC errors do NOT count as failure.
+int GPTData::LoadSecondTableAsMain(void) {
+ uint64_t seekTo;
uint32_t sizeOfParts, newCRC;
+ int retval = 1;
- if ((fd = open(device, O_RDONLY)) != -1) {
- seekTo = secondHeader.partitionEntriesLBA * (off_t) blockSize;
- if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
+ if (myDisk.OpenForRead(device)) {
+ seekTo = secondHeader.partitionEntriesLBA;
+ retval = myDisk.Seek(seekTo);
+ if (retval == 1) {
SetGPTSize(secondHeader.numParts);
sizeOfParts = secondHeader.numParts * secondHeader.sizeOfPartitionEntries;
- if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
+ if (myDisk.Read(partitions, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Read error %d! Misbehavior now likely!\n", errno);
+ retval = 0;
} // if
newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
@@ -770,11 +815,13 @@ void GPTData::LoadSecondTableAsMain(void) {
printf("Error! After loading backup partitions, the CRC still doesn't check out!\n");
} // if
} else {
- printf("Error! Couldn't seek to backup partition table!\n");
+ printf("Error! Couldn't seek to backup partition table!\n", retval);
} // if/else
} else {
printf("Error! Couldn't open device %s when recovering backup partition table!\n", device);
+ retval = 0;
} // if/else
+ return retval;
} // GPTData::LoadSecondTableAsMain()
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
@@ -782,7 +829,6 @@ void GPTData::LoadSecondTableAsMain(void) {
int GPTData::SaveGPTData(int quiet) {
int allOK = 1;
char answer, line[256];
- int fd;
uint64_t secondTable;
uint32_t numParts;
off_t offset;
@@ -851,8 +897,7 @@ int GPTData::SaveGPTData(int quiet) {
if ((allOK) && (!quiet)) {
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("MBR PARTITIONS!!\n\n");
printf("Do you want to proceed, possibly destroying your data? ");
answer = GetYN();
if (answer == 'Y') {
@@ -864,55 +909,53 @@ int GPTData::SaveGPTData(int quiet) {
// Do it!
if (allOK) {
- fd = OpenForWrite(device);
- if (fd != -1) {
- // First, write the protective MBR...
- protectiveMBR.WriteMBRData(fd);
+ // First, write the protective MBR...
+ allOK = protectiveMBR.WriteMBRData(&myDisk);
+ if (allOK && myDisk.OpenForWrite(device)) {
// Now write the main GPT header...
- 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)
+ if (myDisk.Seek(1) == 1) {
+ if (myDisk.Write(&mainHeader, 512) != 512)
+ allOK = 0;
+ } else allOK = 0; // if (myDisk.Seek()...)
// Now write the main partition tables...
if (allOK) {
- offset = mainHeader.partitionEntriesLBA * blockSize;
- if (lseek64(fd, offset, SEEK_SET) != (off_t) - 1) {
- if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
- allOK = 0;
- } else allOK = 0; // if (lseek64()...)
+ offset = mainHeader.partitionEntriesLBA;
+ if (myDisk.Seek(offset)) {
+ if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
+ allOK = 0;
+ } else allOK = 0; // if (myDisk.Seek()...)
} // if (allOK)
// Now seek to near the end to write the secondary GPT....
if (allOK) {
- offset = (off_t) secondTable * (off_t) (blockSize);
- if (lseek64(fd, offset, SEEK_SET) == (off_t) - 1) {
+ offset = (off_t) secondTable;
+ if (myDisk.Seek(offset) != 1) {
allOK = 0;
- printf("Unable to seek to end of disk!\n");
+ printf("Unable to seek to end of disk! Perhaps the 'e' option on the experts' menu\n"
+ "will resolve this problem.\n");
} // if
} // if
// Now write the secondary partition tables....
if (allOK) {
- if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
+ if (myDisk.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0;
} // if (allOK)
// Now write the secondary GPT header...
if (allOK) {
- offset = mainHeader.backupLBA * blockSize;
- if (lseek64(fd, offset, SEEK_SET) != (off_t) - 1) {
- if (myWrite(fd, (char*) &secondHeader, 512) == -1)
+ offset = mainHeader.backupLBA;
+ if (myDisk.Seek(offset)) {
+ if (myDisk.Write(&secondHeader, 512) == -1)
allOK = 0;
- } else allOK = 0; // if (lseek64()...)
+ } else allOK = 0; // if (myDisk.Seek()...)
} // if (allOK)
// re-read the partition table
if (allOK) {
- DiskSync(fd);
+ myDisk.DiskSync();
} // if
if (allOK) { // writes completed OK
@@ -922,7 +965,7 @@ int GPTData::SaveGPTData(int quiet) {
printf("MIGHT be harmless, but you may have trashed the disk! Use parted and, if\n");
printf("necessary, restore your original partition table.\n");
} // if/else
- close(fd);
+ myDisk.Close();
} else {
fprintf(stderr, "Unable to open device %s for writing! Errno is %d! Aborting write!\n",
device, errno);
@@ -952,8 +995,10 @@ int GPTData::SaveGPTData(int quiet) {
int GPTData::SaveGPTBackup(char* filename) {
int fd, allOK = 1;
uint32_t numParts;
+ DiskIO backupFile;
- if ((fd = open(filename, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) {
+// if ((fd = open(filename, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) {
+ if (backupFile.OpenForWrite(filename)) {
// Reverse the byte order, if necessary....
numParts = mainHeader.numParts;
if (IsLittleEndian() == 0) {
@@ -969,21 +1014,24 @@ int GPTData::SaveGPTBackup(char* filename) {
RecomputeCRCs();
// Now write the protective MBR...
- protectiveMBR.WriteMBRData(fd);
+ protectiveMBR.WriteMBRData(&backupFile);
// Now write the main GPT header...
if (allOK)
- if (myWrite(fd, (char*) &mainHeader, 512) == -1)
+ // MBR write closed disk, so re-open and seek to end....
+ backupFile.OpenForWrite();
+ backupFile.Seek(1);
+ if (backupFile.Write(&mainHeader, 512) == -1)
allOK = 0;
// Now write the secondary GPT header...
if (allOK)
- if (myWrite(fd, (char*) &secondHeader, 512) == -1)
+ if (backupFile.Write(&secondHeader, 512) == -1)
allOK = 0;
// Now write the main partition tables...
if (allOK) {
- if (myWrite(fd, (char*) partitions, GPT_SIZE * numParts) == -1)
+ if (backupFile.Write(partitions, GPT_SIZE * numParts) == -1)
allOK = 0;
} // if
@@ -993,7 +1041,7 @@ int GPTData::SaveGPTBackup(char* filename) {
printf("Warning! An error was reported when writing the backup file.\n");
printf("It may not be usable!\n");
} // if/else
- close(fd);
+ backupFile.Close();
// Now reverse the byte-order reversal, if necessary....
if (IsLittleEndian() == 0) {
@@ -1016,17 +1064,19 @@ int GPTData::LoadGPTBackup(char* filename) {
int fd, allOK = 1, val;
uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC;
int littleEndian = 1;
+ DiskIO backupFile;
- if ((fd = open(filename, O_RDONLY)) != -1) {
+// if ((fd = open(filename, O_RDONLY)) != -1) {
+ if (backupFile.OpenForRead(filename)) {
if (IsLittleEndian() == 0)
littleEndian = 0;
// Let the MBRData class load the saved MBR...
- protectiveMBR.ReadMBRData(fd, 0); // 0 = don't check block size
+ protectiveMBR.ReadMBRData(&backupFile, 0); // 0 = don't check block size
// Load the main GPT header, check its vaility, and set the GPT
// size based on the data
- if (myRead(fd, (char*) &mainHeader, 512)) {
+ if (backupFile.Read(&mainHeader, 512) != 512) {
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if
mainCrcOk = CheckHeaderCRC(&mainHeader);
@@ -1038,7 +1088,7 @@ int GPTData::LoadGPTBackup(char* filename) {
// Load the backup GPT header in much the same way as the main
// GPT header....
- if (myRead(fd, (char*) &secondHeader, 512) != 512) {
+ if (backupFile.Read(&secondHeader, 512) != 512) {
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if
secondCrcOk = CheckHeaderCRC(&secondHeader);
@@ -1074,7 +1124,7 @@ int GPTData::LoadGPTBackup(char* filename) {
// Load main partition table, and record whether its CRC
// matches the stored value
sizeOfParts = numParts * sizeOfEntries;
- if (myRead(fd, (char*) partitions, sizeOfParts) != sizeOfParts) {
+ if (backupFile.Read(partitions, sizeOfParts) != sizeOfParts) {
fprintf(stderr, "Warning! Read error %d; strange behavior now likely!\n", errno);
} // if
@@ -1136,8 +1186,9 @@ void GPTData::DisplayGPTData(void) {
uint64_t temp, totalFree;
BytesToSI(diskSize * blockSize, sizeInSI);
- printf("Disk %s: %llu sectors, %s\n", device,
- (unsigned long long) diskSize, sizeInSI);
+ printf("Disk %s: %llu sectors, ", device,
+ (unsigned long long) diskSize);
+ printf("%s\n", 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);
@@ -1145,8 +1196,8 @@ void GPTData::DisplayGPTData(void) {
(unsigned long long) mainHeader.firstUsableLBA,
(unsigned long long) mainHeader.lastUsableLBA);
totalFree = FindFreeBlocks(&i, &temp);
- printf("Total free space is %llu sectors (%s)\n", (unsigned long long) totalFree,
- BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
+ printf("Total free space is %llu sectors ", (unsigned long long) totalFree);
+ printf("(%s)\n", BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
for (i = 0; i < mainHeader.numParts; i++) {
partitions[i].ShowSummary(i, blockSize);
@@ -1269,7 +1320,7 @@ void GPTData::CreatePartition(void) {
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
partitions[partNum].ChangeType();
- partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType(prompt));
+ partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType().c_str());
} else {
printf("No free sectors available\n");
} // if/else
@@ -1339,32 +1390,32 @@ int GPTData::DestroyGPT(int prompt) {
goOn = GetYN();
} // if
if (goOn == 'Y') {
- fd = open(device, O_WRONLY);
+/* OpenForWrite(device);
#ifdef __APPLE__
// MacOS X requires a shared lock under some circumstances....
if (fd < 0) {
fd = open(device, O_WRONLY|O_SHLOCK);
} // if
-#endif
- if (fd != -1) {
- lseek64(fd, mainHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
- if (myWrite(fd, blankSector, 512) != 512) { // blank it out
+#endif */
+ if (myDisk.OpenForWrite(device)) {
+ myDisk.Seek(mainHeader.currentLBA); // seek to GPT header
+ if (myDisk.Write(blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! GPT main header not overwritten! Error is %d\n", errno);
} // if
- lseek64(fd, mainHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
+ myDisk.Seek(mainHeader.partitionEntriesLBA); // 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);
+ sum = myDisk.Write(emptyTable, tableSize);
if (sum != tableSize)
fprintf(stderr, "Warning! GPT main partition table not overwritten! Error is %d\n", errno);
- lseek64(fd, secondHeader.partitionEntriesLBA * blockSize, SEEK_SET); // seek to partition table
- sum = myWrite(fd, emptyTable, tableSize);
+ myDisk.Seek(secondHeader.partitionEntriesLBA); // seek to partition table
+ sum = myDisk.Write(emptyTable, tableSize);
if (sum != tableSize)
fprintf(stderr, "Warning! GPT backup partition table not overwritten! Error is %d\n", errno);
- lseek64(fd, secondHeader.currentLBA * blockSize, SEEK_SET); // seek to GPT header
- if (myWrite(fd, blankSector, 512) != 512) { // blank it out
+ myDisk.Seek(secondHeader.currentLBA); // seek to GPT header
+ if (myDisk.Write(blankSector, 512) != 512) { // blank it out
fprintf(stderr, "Warning! GPT backup header not overwritten! Error is %d\n", errno);
} // if
if (prompt > 0) {
@@ -1377,16 +1428,16 @@ int GPTData::DestroyGPT(int prompt) {
// had subsequently discarded (say, if it conflicted with older GPT
// structures).
if ((blank == 'Y') || (prompt < 0)) {
- lseek64(fd, 0, SEEK_SET);
- if (myWrite(fd, blankSector, 512) != 512) { // blank it out
+ myDisk.Seek(0);
+ if (myDisk.Write(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");
} // if/else
- DiskSync(fd);
- close(fd);
+ myDisk.DiskSync();
+ myDisk.Close();
printf("GPT data structures destroyed! You may now partition the disk using fdisk or\n"
"other utilities. Program will now terminate.\n");
} else {
@@ -1695,7 +1746,7 @@ int GPTData::XFormToMBR(void) {
printf("\nCreating entry for partition #%d\n", j + 1);
numConverted += OnePartToMBR(j, i);
} // for
- printf("MBR writing returned %d\n", protectiveMBR.WriteMBRData(device));
+ printf("MBR writing returned %d\n", protectiveMBR.WriteMBRData(&myDisk));
return numConverted;
} // GPTData::XFormToMBR()
@@ -1811,7 +1862,8 @@ int GPTData::SetGPTSize(uint32_t numEntries) {
// partition table, which causes problems when loading data from a RAID
// array that's been expanded because this function is called when loading
// data.
- if ((numEntries != mainHeader.numParts) || (partitions == NULL)) {
+ if ((numEntries != mainHeader.numParts) || (numEntries != secondHeader.numParts)
+ || (partitions == NULL)) {
newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart));
if (newParts != NULL) {
if (partitions != NULL) { // existing partitions; copy them over
@@ -1908,15 +1960,12 @@ int GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t en
// Sort the GPT entries, eliminating gaps and making for a logical
// ordering. Relies on QuickSortGPT() for the bulk of the work
void GPTData::SortGPT(void) {
- int i, lastPart = 0;
GPTPart temp;
+ uint32_t i, numFound, firstPart, lastPart;
// First, find the last partition with data, so as not to
// spend needless time sorting empty entries....
- for (i = 0; i < mainHeader.numParts; i++) {
- if (partitions[i].GetFirstLBA() > 0)
- lastPart = i;
- } // for
+ numFound = GetPartRange(&firstPart, &lastPart);
// Now swap empties with the last partitions, to simplify the logic
// in the Quicksort function....
@@ -1926,11 +1975,18 @@ void GPTData::SortGPT(void) {
temp = partitions[i];
partitions[i] = partitions[lastPart];
partitions[lastPart] = temp;
- lastPart--;
+ do {
+ lastPart--;
+ } while ((lastPart > 0) && (partitions[lastPart].GetFirstLBA() == 0));
} // if
i++;
} // while
+ // If there are more empties than partitions in the range from 0 to lastPart,
+ // the above leaves lastPart set too high, so we've got to adjust it to
+ // prevent empties from migrating to the top of the list....
+ GetPartRange(&firstPart, &lastPart);
+
// Now call the recursive quick sort routine to do the real work....
QuickSortGPT(partitions, 0, lastPart);
} // GPTData::SortGPT()
diff --git a/gpt.h b/gpt.h
index 30cd75f..1d605b5 100644
--- a/gpt.h
+++ b/gpt.h
@@ -6,7 +6,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <sys/ioctl.h>
+#include "gptpart.h"
#include "support.h"
#include "parttypes.h"
#include "mbr.h"
@@ -16,7 +16,7 @@
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
-#define GPTFDISK_VERSION "0.6.1"
+#define GPTFDISK_VERSION "0.6.2-pre1"
using namespace std;
@@ -60,6 +60,7 @@ protected:
struct GPTHeader secondHeader;
MBRData protectiveMBR;
char device[256]; // device filename
+ DiskIO myDisk;
uint32_t blockSize; // device block size
uint64_t diskSize; // size of device, in blocks
GPTValidity state; // is GPT valid?
@@ -93,11 +94,11 @@ public:
// Load or save data from/to disk
int LoadMBR(char* f) {return protectiveMBR.ReadMBRData(f);}
- void PartitionScan(int fd);
+ void PartitionScan(void);
int LoadPartitions(char* deviceFilename);
- int ForceLoadGPTData(int fd);
+ int ForceLoadGPTData(void);
int LoadMainTable(void);
- void LoadSecondTableAsMain(void);
+ int LoadSecondTableAsMain(void);
int SaveGPTData(int quiet = 0);
int SaveGPTBackup(char* filename);
int LoadGPTBackup(char* filename);
diff --git a/gptpart.cc b/gptpart.cc
index 5ee7d5d..076f115 100644
--- a/gptpart.cc
+++ b/gptpart.cc
@@ -35,11 +35,14 @@ GPTPart::~GPTPart(void) {
} // destructor
// Return partition's name field
-unsigned char* GPTPart::GetName(unsigned char* ref) {
- if (ref == NULL)
+string GPTPart::GetName(void) {
+ string theName;
+
+/* if (ref == NULL)
ref = (unsigned char*) malloc(NAME_SIZE * sizeof (unsigned char));
- strcpy((char*) ref, (char*) name);
- return ref;
+ strcpy((char*) ref, (char*) name); */
+ theName = (const char*) name;
+ return theName;
} // GPTPart::GetName()
// Return the gdisk-specific two-byte hex code for the partition
@@ -49,8 +52,13 @@ uint16_t GPTPart::GetHexType(void) {
// Return a plain-text description of the partition type (e.g., "Linux/Windows
// data" or "Linux swap").
-char* GPTPart::GetNameType(char* theName) {
- return typeHelper.GUIDToName(partitionType, theName);
+string GPTPart::GetNameType(void) {
+ string temp;
+ char theName[255];
+
+ temp = typeHelper.GUIDToName(partitionType, theName);
+
+ return temp;
} // GPTPart::GetNameType()
// Compute and return the partition's length (or 0 if the end is incorrectly
@@ -162,13 +170,13 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
printf("(%s)\n", typeHelper.GUIDToName(partitionType, temp));
printf("Partition unique GUID: %s\n", GUIDToStr(uniqueGUID, temp));
- printf("First sector: %llu (at %s)\n", (unsigned long long) firstLBA,
- BytesToSI(firstLBA * blockSize, temp));
- printf("Last sector: %llu (at %s)\n", (unsigned long long) lastLBA,
- BytesToSI(lastLBA * blockSize, temp));
+ printf("First sector: %llu ", firstLBA);
+ printf("(at %s)\n", BytesToSI(firstLBA * blockSize, temp));
+ printf("Last sector: %llu ", (unsigned long long) lastLBA);
+ printf("(at %s)\n", BytesToSI(lastLBA * blockSize, temp));
size = (lastLBA - firstLBA + 1);
- printf("Partition size: %llu sectors (%s)\n", (unsigned long long)
- size, BytesToSI(size * ((uint64_t) blockSize), temp));
+ printf("Partition size: %llu sectors ", (unsigned long long) size);
+ printf("(%s)\n", BytesToSI(size * ((uint64_t) blockSize), temp));
printf("Attribute flags: %016llx\n", (unsigned long long) attributes);
printf("Partition name: ");
i = 0;
@@ -189,17 +197,18 @@ void GPTPart::ChangeType(void) {
char typeName[255], line[255];
char* junk;
int typeNum = 0xFFFF;
-// uint16_t typeNum = 0xFFFF;
GUIDData newType;
- printf("Current type is '%s'\n", GetNameType(line));
-// printf("Current type is '%s'\n", typeHelper.GUIDToName(partitionType, typeName));
+ printf("Current type is '%s'\n", GetNameType().c_str());
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
- printf("Hex code (L to show codes, 0 to enter raw code): ");
+ printf("Hex code (L to show codes, 0 to enter raw code, Enter = 0700): ");
junk = fgets(line, 255, stdin);
sscanf(line, "%X", &typeNum);
if ((line[0] == 'L') || (line[0] == 'l'))
typeHelper.ShowTypes();
+ if (line[0] == '\n') {
+ typeNum = 0x0700;
+ } // if
} // while
if (typeNum != 0) // user entered a code, so convert it
newType = typeHelper.IDToGUID((uint16_t) typeNum);
diff --git a/gptpart.h b/gptpart.h
index b1a580f..2ae27e3 100644
--- a/gptpart.h
+++ b/gptpart.h
@@ -16,8 +16,8 @@
#define __GPTPART_H
#include <stdint.h>
+#include <string>
#include <sys/types.h>
-#include <sys/ioctl.h>
#include "support.h"
#include "parttypes.h"
@@ -53,13 +53,13 @@ class GPTPart {
// Simple data retrieval:
struct GUIDData GetType(void) {return partitionType;}
uint16_t GetHexType(void);
- char* GetNameType(char* theName);
+ string GetNameType(void);
struct GUIDData GetUniqueGUID(void) {return uniqueGUID;}
uint64_t GetFirstLBA(void) {return firstLBA;}
uint64_t GetLastLBA(void) {return lastLBA;}
uint64_t GetLengthLBA(void);
uint64_t GetAttributes(void) {return attributes;}
- unsigned char* GetName(unsigned char* theName);
+ string GetName(void);
// Simple data assignment:
void SetType(struct GUIDData t) {partitionType = t;}
diff --git a/mbr.cc b/mbr.cc
index f51d5c7..029b576 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -70,14 +70,12 @@ MBRData::~MBRData(void) {
int MBRData::ReadMBRData(char* deviceFilename) {
int fd, allOK = 1;
- if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
- ReadMBRData(fd);
+ if (myDisk->OpenForRead(deviceFilename)) {
+ ReadMBRData(myDisk);
} else {
allOK = 0;
} // if
- close(fd);
-
if (allOK)
strcpy(device, deviceFilename);
@@ -89,94 +87,101 @@ int MBRData::ReadMBRData(char* deviceFilename) {
// Note that any extended partition(s) present will be explicitly stored
// in the partitions[] array, along with their contained partitions; the
// extended container partition(s) should be ignored by other functions.
-void MBRData::ReadMBRData(int fd, int checkBlockSize) {
+void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
int allOK = 1, i, j, logicalNum;
- int err;
+ int err = 1;
TempMBR tempMBR;
+ myDisk = theDisk;
+
// Empty existing MBR data, including the logical partitions...
EmptyMBR(0);
- err = lseek64(fd, 0, SEEK_SET);
- err = myRead(fd, (char*) &tempMBR, 512);
- for (i = 0; i < 440; i++)
- code[i] = tempMBR.code[i];
- diskSignature = tempMBR.diskSignature;
- nulls = tempMBR.nulls;
- for (i = 0; i < 4; i++) {
- partitions[i].status = tempMBR.partitions[i].status;
- partitions[i].partitionType = tempMBR.partitions[i].partitionType;
- partitions[i].firstLBA = tempMBR.partitions[i].firstLBA;
- partitions[i].lengthLBA = tempMBR.partitions[i].lengthLBA;
- for (j = 0; j < 3; j++) {
- partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
- partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
- } // for j... (reading parts of CHS geometry)
- } // for i... (reading all four partitions)
- MBRSignature = tempMBR.MBRSignature;
-
- // Reverse the byte order, if necessary
- if (IsLittleEndian() == 0) {
- ReverseBytes(&diskSignature, 4);
- ReverseBytes(&nulls, 2);
- ReverseBytes(&MBRSignature, 2);
+ if (myDisk->Seek(0))
+ if (myDisk->Read(&tempMBR, 512))
+ err = 0;
+ if (err) {
+ fprintf(stderr, "Problem reading disk in MBRData::ReadMBRData!\n");
+ } else {
+ for (i = 0; i < 440; i++)
+ code[i] = tempMBR.code[i];
+ diskSignature = tempMBR.diskSignature;
+ nulls = tempMBR.nulls;
for (i = 0; i < 4; i++) {
- ReverseBytes(&partitions[i].firstLBA, 4);
- ReverseBytes(&partitions[i].lengthLBA, 4);
- } // for
- } // if
-
- if (MBRSignature != MBR_SIGNATURE) {
- allOK = 0;
- state = invalid;
- } // if
-
- // Find disk size
- diskSize = disksize(fd, &err);
-
- // Find block size
- if (checkBlockSize) {
- blockSize = GetBlockSize(fd);
- } // if (checkBlockSize)
+ partitions[i].status = tempMBR.partitions[i].status;
+ partitions[i].partitionType = tempMBR.partitions[i].partitionType;
+ partitions[i].firstLBA = tempMBR.partitions[i].firstLBA;
+ partitions[i].lengthLBA = tempMBR.partitions[i].lengthLBA;
+ for (j = 0; j < 3; j++) {
+ partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
+ partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
+ } // for j... (reading parts of CHS geometry)
+ } // for i... (reading all four partitions)
+ MBRSignature = tempMBR.MBRSignature;
+
+ // Reverse the byte order, if necessary
+ if (IsLittleEndian() == 0) {
+ ReverseBytes(&diskSignature, 4);
+ ReverseBytes(&nulls, 2);
+ ReverseBytes(&MBRSignature, 2);
+ for (i = 0; i < 4; i++) {
+ ReverseBytes(&partitions[i].firstLBA, 4);
+ ReverseBytes(&partitions[i].lengthLBA, 4);
+ } // for
+ } // if
- // Load logical partition data, if any is found....
- if (allOK) {
- for (i = 0; i < 4; i++) {
- if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
- || (partitions[i].partitionType == 0x85)) {
- // Found it, so call a recursive algorithm to load everything from them....
- logicalNum = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), 4);
- if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
- allOK = 0;
- fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
- } // if maxLogicals valid
- } // if primary partition is extended
- } // for primary partition loop
- if (allOK) { // Loaded logicals OK
- state = mbr;
- } else {
+ if (MBRSignature != MBR_SIGNATURE) {
+ allOK = 0;
state = invalid;
} // if
- } // if
- /* Check to see if it's in GPT format.... */
- if (allOK) {
- for (i = 0; i < 4; i++) {
- if (partitions[i].partitionType == UINT8_C(0xEE)) {
- state = gpt;
+ // Find disk size
+ diskSize = myDisk->DiskSize(&err);
+
+ // Find block size
+ if (checkBlockSize) {
+ blockSize = myDisk->GetBlockSize();
+ } // if (checkBlockSize)
+
+ // Load logical partition data, if any is found....
+ if (allOK) {
+ for (i = 0; i < 4; i++) {
+ if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
+ || (partitions[i].partitionType == 0x85)) {
+ // Found it, so call a recursive algorithm to load everything from them....
+ logicalNum = ReadLogicalPart(partitions[i].firstLBA, UINT32_C(0), 4);
+ if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
+ allOK = 0;
+ fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
+ } // if maxLogicals valid
+ } // if primary partition is extended
+ } // for primary partition loop
+ if (allOK) { // Loaded logicals OK
+ state = mbr;
+ } else {
+ state = invalid;
} // if
- } // for
- } // if
+ } // if
- // If there's an EFI GPT partition, look for other partition types,
- // to flag as hybrid
- if (state == gpt) {
- for (i = 0 ; i < 4; i++) {
- if ((partitions[i].partitionType != UINT8_C(0xEE)) &&
- (partitions[i].partitionType != UINT8_C(0x00)))
- state = hybrid;
- } // for
- } // if (hybrid detection code)
+ /* Check to see if it's in GPT format.... */
+ if (allOK) {
+ for (i = 0; i < 4; i++) {
+ if (partitions[i].partitionType == UINT8_C(0xEE)) {
+ state = gpt;
+ } // if
+ } // for
+ } // if
+
+ // If there's an EFI GPT partition, look for other partition types,
+ // to flag as hybrid
+ if (state == gpt) {
+ for (i = 0 ; i < 4; i++) {
+ if ((partitions[i].partitionType != UINT8_C(0xEE)) &&
+ (partitions[i].partitionType != UINT8_C(0x00)))
+ state = hybrid;
+ } // for
+ } // if (hybrid detection code)
+ } // no initial error
} // MBRData::ReadMBRData(int fd)
// This is a recursive function to read all the logical partitions, following the
@@ -184,25 +189,25 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
// partitions[] array. Returns last index to partitions[] used, or -1 if there was
// a problem.
// Parameters:
-// fd = file descriptor
// extendedStart = LBA of the start of the extended partition
// diskOffset = LBA offset WITHIN the extended partition of the one to be read
// partNum = location in partitions[] array to store retrieved data
-int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
+int MBRData::ReadLogicalPart(uint32_t extendedStart,
uint32_t diskOffset, int partNum) {
struct TempMBR ebr;
- off_t offset;
+ uint64_t offset;
// Check for a valid partition number. Note that partitions MAY be read into
// the area normally used by primary partitions, although the only calling
// function as of GPT fdisk version 0.5.0 doesn't do so.
if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
- offset = (off_t) (extendedStart + diskOffset) * blockSize;
- if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
+ offset = (uint64_t) (extendedStart + diskOffset);
+// if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
+ if (myDisk->Seek(offset) == 0) { // seek to EBR record
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
partNum = -1;
}
- if (myRead(fd, (char*) &ebr, 512) != 512) { // Load the data....
+ if (myDisk->Read(&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;
@@ -229,7 +234,7 @@ int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
// Find the next partition (if there is one) and recurse....
if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 4) &&
(partNum < (MAX_MBR_PARTS - 1))) {
- partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
+ partNum = ReadLogicalPart(extendedStart, ebr.partitions[1].firstLBA,
partNum + 1);
} else {
partNum++;
@@ -243,19 +248,19 @@ int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
int MBRData::WriteMBRData(void) {
int allOK = 1, fd;
- if ((fd = open(device, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) {
- WriteMBRData(fd);
+ if (myDisk->OpenForWrite(device) != 0) {
+ allOK = WriteMBRData(myDisk);
} else {
allOK = 0;
} // if/else
- close(fd);
+ myDisk->Close();
return allOK;
} // MBRData::WriteMBRData(void)
// Save the MBR data to a file. Note that this function writes ONLY the
// MBR data, not the logical partitions (if any are defined).
-void MBRData::WriteMBRData(int fd) {
- int i, j;
+int MBRData::WriteMBRData(DiskIO *theDisk) {
+ int i, j, allOK;
TempMBR tempMBR;
// Reverse the byte order, if necessary
@@ -288,10 +293,17 @@ void MBRData::WriteMBRData(int fd) {
} // for i...
// Now write that data structure...
- lseek64(fd, 0, SEEK_SET);
- if (myWrite(fd, (char*) &tempMBR, 512) != 512) {
- fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
- } // if
+ allOK = theDisk->OpenForWrite();
+ if (allOK && theDisk->Seek(0)) {
+ if (theDisk->Write(&tempMBR, 512) != 512) {
+ allOK = 0;
+ fprintf(stderr, "Warning! Error %d when saving MBR!\n", errno);
+ } // if
+ } else {
+ allOK = 0;
+ fprintf(stderr, "Warning! Error %d when seeking to MBR to write it!\n", errno);
+ } // if/else
+ theDisk->Close();
// Reverse the byte order back, if necessary
if (IsLittleEndian() == 0) {
@@ -303,7 +315,8 @@ void MBRData::WriteMBRData(int fd) {
ReverseBytes(&partitions[i].lengthLBA, 4);
} // for
}// if
-} // MBRData::WriteMBRData(int fd)
+ return allOK;
+} // MBRData::WriteMBRData(DiskIO theDisk)
int MBRData::WriteMBRData(char* deviceFilename) {
strcpy(device, deviceFilename);
@@ -336,8 +349,8 @@ void MBRData::DisplayMBRData(void) {
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
} // if
} // for
- printf("\nDisk size is %llu sectors (%s)\n", (unsigned long long) diskSize,
- BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
+ printf("\nDisk size is %llu sectors ", (unsigned long long) diskSize);
+ printf("(%s)\n", BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
} // MBRData::DisplayMBRData()
// Displays the state, as a word, on stdout. Used for debugging & to
@@ -588,12 +601,12 @@ int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
length32 = (uint32_t) length64;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
- (partitions[i].partitionType != 0xEE)) {
+ (partitions[i].partitionType != 0xEE)) {
DeletePartition(i);
if (state == hybrid)
OptimizeEESize();
deleted = 1;
- } // if (match found)
+ } // if (match found)
} // for i (partition scan)
} // if (hybrid & GPT partition < 2TiB)
return deleted;
@@ -794,7 +807,7 @@ GPTPart MBRData::AsGPT(int i) {
newPart.SetType(((uint16_t) origType) * 0x0100);
newPart.SetUniqueGUID(1);
newPart.SetAttributes(0);
- newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
+ newPart.SetName((unsigned char*) newPart.GetNameType().c_str());
} // if not extended, protective, or non-existent
} // if (origPart != NULL)
return newPart;
diff --git a/mbr.h b/mbr.h
index 0cd4d2a..c8711fc 100644
--- a/mbr.h
+++ b/mbr.h
@@ -5,8 +5,8 @@
#include <stdint.h>
#include <sys/types.h>
-#include <sys/ioctl.h>
#include "gptpart.h"
+#include "diskio.h"
#ifndef __MBRSTRUCTS
#define __MBRSTRUCTS
@@ -41,9 +41,7 @@ struct MBRRecord {
}; // struct MBRRecord
// A 512-byte data structure into which the MBR can be loaded in one
-// go, for the benefit of FreeBSD which seems to flake out when loading
-// from block devices in multiples other than the block size.
-// Also used when loading logical partitions.
+// go. Also used when loading logical partitions.
#pragma pack(1)
struct TempMBR {
uint8_t code[440];
@@ -72,6 +70,7 @@ protected:
uint64_t diskSize; // size in blocks
uint64_t numHeads; // number of heads, in CHS scheme
uint64_t numSecspTrack; // number of sectors per track, in CHS scheme
+ DiskIO* myDisk;
char device[256];
MBRValidity state;
struct MBRRecord* GetPartition(int i); // Return primary or logical partition
@@ -82,13 +81,13 @@ public:
// File I/O functions...
int ReadMBRData(char* deviceFilename);
- void ReadMBRData(int fd, int checkBlockSize = 1);
+ void ReadMBRData(DiskIO * theDisk, int checkBlockSize = 1);
// ReadLogicalPart() returns last partition # read to logicals[] array,
// or -1 if there was a problem....
- int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
+ int ReadLogicalPart(uint32_t extendedStart, uint32_t diskOffset,
int partNum);
int WriteMBRData(void);
- void WriteMBRData(int fd);
+ int WriteMBRData(DiskIO *theDisk);
int WriteMBRData(char* deviceFilename);
// Display data for user...
diff --git a/support.cc b/support.cc
index 81801f3..388b71a 100644
--- a/support.cc
+++ b/support.cc
@@ -9,9 +9,8 @@
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
-#include <sys/ioctl.h>
#include <stdio.h>
-#include <string.h>
+#include <string>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
@@ -27,10 +26,6 @@
#define BLKPBSZGET _IO(0x12,123)
#endif
-// Below constant corresponds to an 800GB disk -- a somewhat arbitrary
-// cutoff
-#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600)
-
using namespace std;
// Get a numeric value from the user, between low and high (inclusive).
@@ -205,114 +200,6 @@ char* BytesToSI(uint64_t size, char theValue[]) {
return theValue;
} // BlocksToSI()
-// Returns block size of device pointed to by fd file descriptor. If the ioctl
-// returns an error condition, print a warning but return a value of SECTOR_SIZE
-// (512)..
-int GetBlockSize(int fd) {
- int err = -1, result;
-
-#ifdef __APPLE__
- err = ioctl(fd, DKIOCGETBLOCKSIZE, &result);
-#endif
-#ifdef __FreeBSD__
- err = ioctl(fd, DIOCGSECTORSIZE, &result);
-#endif
-#ifdef __linux__
- err = ioctl(fd, BLKSSZGET, &result);
-#endif
-
- if (err == -1) {
- result = SECTOR_SIZE;
- // ENOTTY = inappropriate ioctl; probably being called on a disk image
- // file, so don't display the warning message....
- // 32-bit code returns EINVAL, I don't know why. I know I'm treading on
- // thin ice here, but it should be OK in all but very weird cases....
- if ((errno != ENOTTY) && (errno != EINVAL)) {
- printf("\aError %d when determining sector size! Setting sector size to %d\n",
- errno, SECTOR_SIZE);
- } // if
- } // if
-
-/* 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 */
-
- return (result);
-} // GetBlockSize()
-
-// My original FindAlignment() function (after this one) isn't working, since
-// the BLKPBSZGET ioctl() isn't doing what I expected (it returns 512 even on
-// a WD Advanced Format drive). Therefore, I'm using a simpler function that
-// returns 1-sector alignment for unusual sector sizes and drives smaller than
-// a size defined by SMALLEST_ADVANCED_FORMAT, and 8-sector alignment for
-// larger drives with 512-byte sectors.
-int FindAlignment(int fd) {
- int err, result;
-
- if ((GetBlockSize(fd) == 512) && (disksize(fd, &err) >= SMALLEST_ADVANCED_FORMAT)) {
- result = 8; // play it safe; align for 4096-byte sectors
- } else {
- result = 1; // unusual sector size; assume it's the real physical size
- } // if/else
- return result;
-} // FindAlignment
-
-// Return the partition alignment value in sectors. Right now this works
-// 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, errnum = 0, result = 8, physicalSectorSize = 4096;
- uint64_t diskSize;
-
- printf("Entering FindAlignment()\n");
-#if defined (__linux__) && defined (BLKPBSZGET)
- err = ioctl(fd, BLKPBSZGET, &physicalSectorSize);
- printf("In FindAlignment(), physicalSectorSize = %d, err = %d\n", physicalSectorSize, err);
-// printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize);
-#else
- err = -1;
-#endif
-
- 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
- } // if/else
- } else { // ioctl worked; compute alignment
- result = physicalSectorSize / GetBlockSize(fd);
- // Disks with larger physical than logical sectors must theoretically
- // have a total disk size that's a multiple of the physical sector
- // size; however, some such disks have compatibility jumper settings
- // meant for one-partition MBR setups, and these reduce the total
- // number of sectors by 1. If such a setting is used, it'll result
- // in improper alignment, so look for this condition and warn the
- // user if it's found....
- diskSize = disksize(fd, &errnum);
- if ((diskSize % (uint64_t) result) != 0) {
- fprintf(stderr, "\aWarning! Disk size (%llu) is not a multiple of alignment\n"
- "size (%d), but it should be! Check disk manual and jumper settings!\n",
- (unsigned long long) diskSize, result);
- } // if
- } // if/else
- if (result <= 0) // can happen if physical sector size < logical sector size
- result = 1;
- 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....
@@ -463,178 +350,3 @@ uint64_t PowerOf2(int value) {
} else retval = 0;
return retval;
} // PowerOf2()
-
-// An extended file-open function. This includes some system-specific checks.
-// I want them in a function because I use these calls twice and I don't want
-// to forget to change them in one location if I need to change them in
-// the other....
-int OpenForWrite(char* deviceFilename) {
- int fd;
-
- fd = open(deviceFilename, O_WRONLY); // try to open the device; may fail....
-#ifdef __APPLE__
- // MacOS X requires a shared lock under some circumstances....
- if (fd < 0) {
- fd = open(deviceFilename, O_WRONLY|O_SHLOCK);
- } // if
-#endif
- return fd;
-} // OpenForWrite()
-
-// Resync disk caches so the OS uses the new partition table. This code varies
-// a lot from one OS to another.
-void DiskSync(int fd) {
- int i;
-
- sync();
-#ifdef __APPLE__
- printf("Warning: The kernel may continue to use old or deleted partitions.\n"
- "You should reboot or remove the drive.\n");
- /* don't know if this helps
- * it definitely will get things on disk though:
- * http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
- i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
-#else
-#ifdef __FreeBSD__
- sleep(2);
- i = ioctl(fd, DIOCGFLUSH);
- printf("Warning: The kernel may continue to use old or deleted partitions.\n"
- "You should reboot or remove the drive.\n");
-#else
- sleep(2);
- i = ioctl(fd, BLKRRPART);
- if (i)
- printf("Warning: The kernel is still using the old partition table.\n"
- "The new table will be used at the next reboot.\n");
-#endif
-#endif
-} // DiskSync()
-
-// 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()
-
-/**************************************************************************************
- * *
- * Below functions are lifted from various sources, as documented in comments before *
- * each one. *
- * *
- **************************************************************************************/
-
-// The disksize function is taken from the Linux fdisk code and modified
-// greatly since then to enable FreeBSD and MacOS support, as well as to
-// return correct values for disk image files.
-uint64_t disksize(int fd, int *err) {
- long sz; // Do not delete; needed for Linux
- long long b; // Do not delete; needed for Linux
- uint64_t sectors = 0; // size in sectors
- off_t bytes = 0; // size in bytes
- struct stat64 st;
-
- // Note to self: I recall testing a simplified version of
- // this code, similar to what's in the __APPLE__ block,
- // on Linux, but I had some problems. IIRC, it ran OK on 32-bit
- // systems but not on 64-bit. Keep this in mind in case of
- // 32/64-bit issues on MacOS....
-#ifdef __APPLE__
- *err = ioctl(fd, DKIOCGETBLOCKCOUNT, &sectors);
-#else
-#ifdef __FreeBSD__
- *err = ioctl(fd, DIOCGMEDIASIZE, &bytes);
- b = GetBlockSize(fd);
- sectors = bytes / b;
-#else
- *err = ioctl(fd, BLKGETSIZE, &sz);
- if (*err) {
- sectors = sz = 0;
- } // if
- if ((errno == EFBIG) || (!*err)) {
- *err = ioctl(fd, BLKGETSIZE64, &b);
- if (*err || b == 0 || b == sz)
- sectors = sz;
- 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
-
- // The above methods have failed (or it's a bum filename reference),
- // so let's assume it's a regular file (a QEMU image, dd backup, or
- // what have you) and see what stat() gives us....
- if ((sectors == 0) || (*err == -1)) {
- if (fstat64(fd, &st) == 0) {
- bytes = (off_t) st.st_size;
- if ((bytes % UINT64_C(512)) != 0)
- fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
- " Misbehavior is likely!\n\a");
- sectors = bytes / UINT64_C(512);
- } // if
- } // if
- return sectors;
-} // disksize()
diff --git a/support.h b/support.h
index b261b76..3a102ae 100644
--- a/support.h
+++ b/support.h
@@ -16,16 +16,17 @@
// Darwin, this may need to be changed back (and in various .cc files).
#include <sys/disk.h>
#define lseek64 lseek
-#else
+#endif
// Linux only....
+#ifdef __linux__
#include <linux/fs.h>
#endif
-#ifdef __FreeBSD__
+/* #ifdef __FreeBSD__
#define fstat64 fstat
#define stat64 stat
-#endif
+#endif */
// Set this as a default
#define SECTOR_SIZE UINT32_C(512)
@@ -55,23 +56,16 @@ struct GUIDData {
uint64_t data2;
}; // struct GUIDData
+static char theFile[255];
+
int GetNumber(int low, int high, int def, const char prompt[]);
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
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);
#endif