Version 0.6.4

This commit is contained in:
srs5694
2010-02-19 17:19:55 -05:00
parent fad064250b
commit 08bb0da079
25 changed files with 642 additions and 656 deletions

View File

@@ -1,6 +1,51 @@
0.6.4 (??/??/2010):
0.6.4 (2/19/2010):
-------------------
- Added -m (--gpttombr) option to sgdisk, enabling conversion of GPT
disks to MBR format, with a limit of four partitions total, and of course
without overcoming the 2TiB limit.
- Added -h (--hybrid) option to sgdisk, enabling creation of hybrid
MBRs. Fewer options are available in sgdisk than in gdisk, though,
in order to keep the user interface manageable.
- Fixed off-by-one bug in specification of partition when using the
-T (--transform-bsd) option in sgdisk.
- Changed the code to create a new MBR unique disk signature whenever a new
protective MBR is generated (when doing an MBR-to-GPT conversion, when
using the 'n' option on the experts' menu, or when using the 'o' option
on the main menu, for example). Previous versions attempted to preserve
the existing MBR disk signature in most cases, but this resulted in
values of 0x00000000 whenever an empty disk was partitioned, and often in
other cases, too. Better to risk changing this value too often than to
leave multiple disks with 0x00000000 values, I think.
- Added transpose ('t' on experts' menu in gdisk; or -r or --transpose in
sgdisk) command to enable fine-tuning partition order without doing a
full sort.
- Added code to clear the MBR boot loader when doing an MBR-to-GPT
conversion. (This was already done in full-disk BSD-to-GPT conversions.)
This is done because I've seen a few problem reports that make me think
some MBR boot loaders freak out and hang the system when they encounter
GPT disks, and/or they attempt to load a second-stage boot loader stored
in what is now GPT territory, causing a system hang. Since MBR boot
loaders don't work on GPT disks anyhow (even GRUB needs to be
reinstalled), this new wiping behavior shouldn't cause any problems, and
may prevent a few.
- Fixed bug in Windows version that prevented saving backup files.
- Fixed bug that caused second and subsequent partition numbers in
prompts in hybrid MBR conversion procedure to be displayed in
hexadecimal.
- Fixed very obscure potential bug in hybrid MBR/GPT synchronization when
deleting partitions; code wasn't matching partition lengths correctly,
which would only affect partitions that start at the same point but have
different lengths in MBR vs. GPT.
- Fixed bug in the -E option to sgdisk; it was actually returning the
last free sector, not the last free sector in the largest free block.

View File

@@ -10,8 +10,8 @@ DEPEND= makedepend $(CFLAGS)
all: gdisk sgdisk
gdisk: $(LIB_OBJS) gdisk.o
$(CXX) $(LIB_OBJS) gdisk.o -L/opt/local/lib -L/usr/local/lib -luuid -o gdisk
gdisk: $(LIB_OBJS) gdisk.o gpttext.o
$(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/opt/local/lib -L/usr/local/lib -luuid -o gdisk
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -luuid -lpopt -o sgdisk

View File

@@ -1,6 +1,6 @@
CC=/usr/bin/i586-mingw32msvc-gcc
CXX=/usr/bin/i586-mingw32msvc-g++
STRIP=/usr/bin/i586-mingw32msvc-strip
CC=/usr/bin/i686-pc-mingw32-gcc
CXX=/usr/bin/i686-pc-mingw32-g++
STRIP=/usr/bin/i686-pc-mingw32-strip
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -g
#CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g

View File

@@ -90,16 +90,28 @@ use a version for another platform, or use a different partitioning tool
altogether.
I compiled gdisk.exe using MinGW (http://www.mingw.org), and in particular
its Linux-hosted cross-compiler. I have not tested the compilability of the
source code under more mainstream Windows compilers, or even on the
Windows-hosted MinGW variant. MinGW was designed for porting Unix
applications to Windows, so it's entirely possible that it will work where
other compilers won't.
its Linux-hosted cross-compiler. Under Ubuntu Linux, the Makefile.mingw
file enables compilation of the software via MinGW. (Type "make -f
Makefile.mingw" to compile the software.) If you try to compile using
another compiler or even using MinGW under Windows or another Linux
variety, you may need to adjust the Makefile.mingw options.
Under Ubuntu Linux, the Makefile.mingw file enables compilation of the
software. (Type "make -f Makefile.mingw" to compile the software.) If you
try to compile using another compiler or even using MinGW under Windows or
another Linux variety, you may need to adjust the Makefile.mingw options.
I've also attempted to compile the code with OpenWatcom 1.8 and Microsoft
Visual C++ 2008 Express. My OpenWatcom attempts failed, mostly because the
compiler can't yet handle iostream output on standard C++ strings.
OpenWatcom also seems to have incorrectly set the value of UINT32_MAX as if
uint32_t values were 64-bit integers. This alone won't cause the compile to
fail, but it would create bugs.
My attemps with Visual C++ were much more successful; after tracking down
and installing a stdint.h file (I used the one from
http://msinttypes.googlecode.com/svn/trunk/stdint.h) and making a few other
minor changes, the code compiled fine, and seems to run properly, although
I've not tested it extensively. I created native projects for both
OpenWatcom and Visual C++, ignoring the Makefile approach, but I'm not
including the relevant project files in the source tarball, since they're
easy enough to regenerate -- just include all the *.h files and all the
*.cc files except diskio-unix.cc and sgdisk.cc, then build.
If you modify GPT fdisk to get it to compile under another compiler, I
welcome submission of patches.

View File

@@ -12,6 +12,7 @@
#include <stdint.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include "attributes.h"
using namespace std;
@@ -20,13 +21,13 @@ using namespace std;
// data.
Attributes::Attributes(void) {
int i;
char temp[ATR_NAME_SIZE];
ostringstream temp;
// Most bits are undefined, so start by giving them an
// appropriate name
for (i = 1; i < NUM_ATR; i++) {
sprintf(temp, "Undefined bit #%d", i);
atNames[i] = temp;
temp << "Undefined bit #" << i;
atNames[i] = temp.str();
} // for
// Now reset those names that are defined....

View File

@@ -2,7 +2,7 @@
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <unistd.h>
//#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "support.h"

12
bsd.cc
View File

@@ -10,7 +10,7 @@
#define __STDC_CONSTANT_MACROS
#include <stdio.h>
#include <unistd.h>
//#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
@@ -37,7 +37,8 @@ BSDData::BSDData(void) {
} // default constructor
BSDData::~BSDData(void) {
delete[] partitions;
if (partitions != NULL)
delete[] partitions;
} // destructor
// Read BSD disklabel data from the specified device filename. This function
@@ -64,9 +65,10 @@ int BSDData::ReadBSDData(const string & device, uint64_t startSector, uint64_t e
// Load the BSD disklabel data from an already-opened disk
// file, starting with the specified sector number.
int BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSector) {
uint8_t buffer[4096]; // I/O buffer
int i, foundSig = 0, bigEnd = 0, allOK = 1;
int allOK = 1;
int i, foundSig = 0, bigEnd = 0;
int relative = 0; // assume absolute partition sector numbering
uint8_t buffer[4096]; // I/O buffer
uint32_t realSig;
uint32_t* temp32;
uint16_t* temp16;
@@ -158,7 +160,7 @@ int BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSect
// detected above, apply a correction to all partition start sectors....
if (relative) {
for (i = 0; i < numParts; i++) {
partitions[i].firstLBA += startSector;
partitions[i].firstLBA += (uint32_t) startSector;
} // for
} // if
} // if signatures OK

5
bsd.h
View File

@@ -55,6 +55,9 @@ struct BSDRecord { // the partition table
};
// Full data in tweaked BSD format
// For some reason this has to be packed or MS Visual C++'s debugger complains
// about memory errors whenever a BSDData variable is destroyed.
#pragma pack (8)
class BSDData {
protected:
// We only need a few items from the main BSD disklabel data structure....
@@ -62,7 +65,7 @@ class BSDData {
uint32_t sectorSize; // # of bytes per sector
uint32_t signature2; // the magic number (again)
uint16_t numParts; // number of partitions in table
BSDRecord* partitions; // partition array
struct BSDRecord* partitions; // partition array
// Above are basic BSD disklabel data; now add more stuff....
uint64_t labelFirstLBA; // first sector of BSD disklabel (partition or disk)

View File

@@ -97,7 +97,8 @@ int DiskIO::OpenForWrite(void) {
// so the file can be re-opened without specifying the filename.
void DiskIO::Close(void) {
if (isOpen)
close(fd);
if (close(fd) < 0)
cerr << "Warning! Problem closing file!\n";
isOpen = 0;
openForWrite = 0;
} // DiskIO::Close()
@@ -117,7 +118,7 @@ int DiskIO::GetBlockSize(void) {
#ifdef __APPLE__
err = ioctl(fd, DKIOCGETBLOCKSIZE, &blockSize);
#endif
#ifdef __FreeBSD__
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
err = ioctl(fd, DIOCGSECTORSIZE, &blockSize);
#endif
#ifdef __linux__
@@ -161,7 +162,7 @@ void DiskIO::DiskSync(void) {
i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
platformFound++;
#endif
#ifdef __FreeBSD__
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
sleep(2);
i = ioctl(fd, DIOCGFLUSH);
cout << "Warning: The kernel may continue to use old or deleted partitions.\n"
@@ -295,8 +296,6 @@ int DiskIO::Write(void* buffer, int numBytes) {
// greatly since then to enable FreeBSD and MacOS support, as well as to
// return correct values for disk image files.
uint64_t DiskIO::DiskSize(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;
@@ -317,13 +316,15 @@ uint64_t DiskIO::DiskSize(int *err) {
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, &sectors);
platformFound++;
#endif
#ifdef __FreeBSD__
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
*err = ioctl(fd, DIOCGMEDIASIZE, &bytes);
b = GetBlockSize();
long long b = GetBlockSize();
sectors = bytes / b;
platformFound++;
#endif
#ifdef __linux__
long sz;
long long b;
*err = ioctl(fd, BLKGETSIZE, &sz);
if (*err) {
sectors = sz = 0;

View File

@@ -19,7 +19,7 @@
#include <winioctl.h>
#define fstat64 fstat
#define stat64 stat
//#define S_IRGRP 0
#define S_IRGRP 0
#define S_IROTH 0
#include <stdio.h>
#include <string>
@@ -93,6 +93,14 @@ int DiskIO::OpenForWrite(void) {
fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
// Preceding call can fail when creating backup files; if so, try
// again with different option...
if (fd == INVALID_HANDLE_VALUE) {
CloseHandle(fd);
fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
} // if
if (fd == INVALID_HANDLE_VALUE) {
CloseHandle(fd);
isOpen = 0;

View File

@@ -25,7 +25,6 @@
#else
#include <sys/ioctl.h>
#endif
#include <stdio.h>
#include <string>
#include <stdint.h>
#include <errno.h>

View File

@@ -25,7 +25,7 @@
#include <sys/ioctl.h>
#endif
#if defined (__FreeBSD__) || defined (__APPLE__)
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
#define fstat64 fstat
#define stat64 stat
#endif

10
gdisk.8
View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH "GDISK" "8" "0.6.3" "Roderick W. Smith" "GPT fdisk Manual"
.TH "GDISK" "8" "0.6.4" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS"
@@ -497,6 +497,14 @@ seem to work, and can sometimes be useful in converting MBR disks. Larger
sizes also work fine. OSes may impose their own limits on the number of
partitions, though.
.TP
.B t
Swap two partitions' entries in the partition table. One partition may be
empty. For instance, if partitions 1\-4 are defined, transposing 1 and 5
results in a table with partitions numbered from 2\-5. Transposing
partitions in this way has no effect on their disk space allocation; it
only alters their order in the partition table.
.TP
.B v
Verify disk. This option is identical to the 'v' option in the main menu.

View File

@@ -9,24 +9,24 @@
//#include <iostream>
#include <stdio.h>
#include <getopt.h>
//#include <getopt.h>
#include <string.h>
#include <string>
#include <iostream>
#include "mbr.h"
#include "gpt.h"
#include "gpttext.h"
#include "support.h"
// Function prototypes....
void MainMenu(string filename, struct GPTData* theGPT);
void MainMenu(string filename, GPTDataTextUI* theGPT);
void ShowCommands(void);
void ExpertsMenu(string filename, struct GPTData* theGPT);
void ExpertsMenu(string filename, GPTDataTextUI* theGPT);
void ShowExpertCommands(void);
void RecoveryMenu(string filename, struct GPTData* theGPT);
void RecoveryMenu(string filename, GPTDataTextUI* theGPT);
void ShowRecoveryCommands(void);
int main(int argc, char* argv[]) {
GPTData theGPT;
GPTDataTextUI theGPT;
int doMore = 1;
char* device = NULL;
@@ -72,7 +72,7 @@ int main(int argc, char* argv[]) {
// Accept a command and execute it. Returns only when the user
// wants to exit (such as after a 'w' or 'q' command).
void MainMenu(string filename, struct GPTData* theGPT) {
void MainMenu(string filename, GPTDataTextUI* theGPT) {
char command, line[255], buFile[255];
char* junk;
int goOn = 1;
@@ -174,7 +174,7 @@ void ShowCommands(void) {
// Accept a recovery & transformation menu command. Returns only when the user
// issues an exit command, such as 'w' or 'q'.
void RecoveryMenu(string filename, struct GPTData* theGPT) {
void RecoveryMenu(string filename, GPTDataTextUI* theGPT) {
char command, line[255], buFile[255];
char* junk;
uint32_t temp1;
@@ -221,10 +221,11 @@ void RecoveryMenu(string filename, struct GPTData* theGPT) {
if (temp1 > 0) {
cout << "Converted " << temp1 << " partitions. Finalize and exit? ";
if (GetYN() == 'Y') {
if (theGPT->DestroyGPT(0) > 0)
if (theGPT->DestroyGPT() > 0)
goOn = 0;
} else {
theGPT->MakeProtectiveMBR();
theGPT->WriteProtectiveMBR();
cout << "Note: New protective MBR created.\n";
} // if/else
} // if
@@ -299,11 +300,10 @@ void ShowRecoveryCommands(void) {
// Accept an experts' menu command. Returns only after the user
// selects an exit command, such as 'w' or 'q'.
void ExpertsMenu(string filename, struct GPTData* theGPT) {
void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
char command, line[255];
char* junk;
uint32_t pn;
uint32_t temp1, temp2;
uint32_t pn, temp1, temp2;
int goOn = 1;
GUIDData aGUID;
@@ -359,10 +359,10 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
break;
case 'p': case 'P':
theGPT->DisplayGPTData();
break;
break;
case 'q': case 'Q':
goOn = 0;
break;
goOn = 0;
break;
case 'r': case 'R':
RecoveryMenu(filename, theGPT);
goOn = 0;
@@ -370,6 +370,9 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
case 's': case 'S':
theGPT->ResizePartitionTable();
break;
case 't': case 'T':
theGPT->SwapPartitions();
break;
case 'v': case 'V':
theGPT->Verify();
break;
@@ -379,7 +382,7 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
} // if
break;
case 'z': case 'Z':
if (theGPT->DestroyGPT() == 1) {
if (theGPT->DestroyGPTwPrompt() == 1) {
goOn = 0;
}
break;
@@ -405,6 +408,7 @@ void ShowExpertCommands(void) {
cout << "q\tquit without saving changes\n";
cout << "r\trecovery and transformation options (experts only)\n";
cout << "s\tresize partition table\n";
cout << "t\ttranspose two partition table entries\n";
cout << "v\tverify disk\n";
cout << "w\twrite table to disk and exit\n";
cout << "z\tzap (destroy) GPT data structures and exit\n";

776
gpt.cc

File diff suppressed because it is too large Load Diff

40
gpt.h
View File

@@ -15,7 +15,13 @@
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
#define GPTFDISK_VERSION "0.6.4-pre1"
#define GPTFDISK_VERSION "0.6.4"
// Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
// numbered value to refer to partition numbers. (Most will be 0 or positive,
// of course.)
#define MBR_EFI_GPT -1
#define MBR_EMPTY -2
using namespace std;
@@ -83,7 +89,7 @@ public:
// Basic necessary functions....
GPTData(void);
GPTData(string deviceFilename);
~GPTData(void);
virtual ~GPTData(void);
// Verify (or update) data integrity
int Verify(void);
@@ -98,6 +104,7 @@ public:
// Load or save data from/to disk
int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);}
int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);}
void PartitionScan(void);
int LoadPartitions(const string & deviceFilename);
int ForceLoadGPTData(void);
@@ -106,32 +113,24 @@ public:
int SaveGPTData(int quiet = 0);
int SaveGPTBackup(const string & filename);
int LoadGPTBackup(const string & filename);
int SaveMBR(void);
int DestroyGPT(void);
int DestroyMBR(void);
// Display data....
void ShowAPMState(void);
void ShowGPTState(void);
void DisplayGPTData(void);
void DisplayMBRData(void) {protectiveMBR.DisplayMBRData();}
void ShowDetails(void);
void ShowPartDetails(uint32_t partNum);
// Request information from the user (& possibly do something with it)
uint32_t GetPartNum(void);
void ResizePartitionTable(void);
void CreatePartition(void);
void DeletePartition(void);
void ChangePartType(void);
void SetAttributes(uint32_t partNum);
int DestroyGPT(int prompt = 1); // Returns 1 if user proceeds
// Convert between GPT and other formats (may require user interaction)
WhichToUse UseWhichPartitions(void);
int XFormPartitions(void);
int XFormDisklabel(int OnGptPart = -1);
int XFormDisklabel(BSDData* disklabel, uint32_t startPart);
// Convert between GPT and other formats
virtual WhichToUse UseWhichPartitions(void);
void XFormPartitions(void);
virtual int XFormDisklabel(uint32_t partNum);
int XFormDisklabel(BSDData* disklabel);
int OnePartToMBR(uint32_t gptPart, int mbrPart); // add one partition to MBR. Returns 1 if successful
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
void MakeHybrid(void);
int PartsToMBR(const int *gptParts, const int *mbrTypes);
// Adjust GPT structures WITHOUT user interaction...
int SetGPTSize(uint32_t numEntries);
@@ -139,6 +138,8 @@ public:
int DeletePartition(uint32_t partNum);
uint32_t CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector);
void SortGPT(void);
void QuickSortGPT(int start, int finish);
int SwapPartitions(uint32_t partNum1, uint32_t partNum2);
int ClearGPTData(void);
void MoveSecondHeaderToEnd();
int SetName(uint32_t partNum, const string & theName = "");
@@ -150,6 +151,7 @@ public:
// Return data about the GPT structures....
int GetPartRange(uint32_t* low, uint32_t* high);
int FindFirstFreePart(void);
uint32_t GetNumParts(void) {return mainHeader.numParts;}
uint64_t GetMainHeaderLBA(void) {return mainHeader.currentLBA;}
uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}

View File

@@ -66,6 +66,11 @@ string GPTPart::GetDescription(void) {
return theName;
} // GPTPart::GetDescription()
// Return 1 if the partition is in use
int GPTPart::IsUsed(void) {
return (firstLBA != UINT64_C(0));
} // GPTPart::IsUsed()
// Set the type code to the specified one. Also changes the partition
// name *IF* the current name is the generic one for the current partition
// type.
@@ -139,6 +144,7 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
if (firstLBA != 0) {
sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1));
cout.fill(' ');
cout.width(4);
cout << partNum + 1 << " ";
cout.width(14);
@@ -256,36 +262,3 @@ void GPTPart::ChangeType(void) {
SetDefaultDescription();
} // if
} // GPTPart::ChangeType()
/***********************************
* Non-class but related functions *
***********************************/
// Recursive quick sort algorithm for GPT partitions. Note that if there
// are any empties in the specified range, they'll be sorted to the
// start, resulting in a sorted set of partitions that begins with
// partition 2, 3, or higher.
void QuickSortGPT(GPTPart* partitions, int start, int finish) {
uint64_t starterValue; // starting location of median partition
int left, right;
GPTPart temp;
left = start;
right = finish;
starterValue = partitions[(start + finish) / 2].GetFirstLBA();
do {
while (partitions[left].GetFirstLBA() < starterValue)
left++;
while (partitions[right].GetFirstLBA() > starterValue)
right--;
if (left <= right) {
temp = partitions[left];
partitions[left] = partitions[right];
partitions[right] = temp;
left++;
right--;
} // if
} while (left <= right);
if (start < right) QuickSortGPT(partitions, start, right);
if (finish > left) QuickSortGPT(partitions, left, finish);
} // QuickSortGPT()

View File

@@ -59,6 +59,7 @@ class GPTPart {
uint64_t GetLengthLBA(void);
uint64_t GetAttributes(void) {return attributes;}
string GetDescription(void);
int IsUsed(void);
// Simple data assignment:
void SetType(PartType t);
@@ -83,7 +84,4 @@ class GPTPart {
void ChangeType(void); // Change the type code
}; // struct GPTPart
// A support function that doesn't quite belong in the class....
void QuickSortGPT(GPTPart* partitions, int start, int finish);
#endif

58
mbr.cc
View File

@@ -10,7 +10,7 @@
#define __STDC_CONSTANT_MACROS
#include <stdio.h>
#include <unistd.h>
//#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
@@ -273,7 +273,7 @@ int MBRData::WriteMBRData(void) {
int allOK = 1;
if (myDisk != NULL) {
if (myDisk->OpenForWrite(device) != 0) {
if (myDisk->OpenForWrite() != 0) {
allOK = WriteMBRData(myDisk);
} else {
allOK = 0;
@@ -493,10 +493,7 @@ void MBRData::EmptyMBR(int clearBootloader) {
// 2-byte nulls area only if requested to do so. (This is the
// default.)
if (clearBootloader == 1) {
for (i = 0; i < 440; i++)
code[i] = 0;
diskSignature = (uint32_t) rand();
nulls = 0;
EmptyBootloader();
} // if
// Blank out the partitions
@@ -515,6 +512,17 @@ void MBRData::EmptyMBR(int clearBootloader) {
MBRSignature = MBR_SIGNATURE;
} // MBRData::EmptyMBR()
// Blank out the boot loader area. Done with the initial MBR-to-GPT
// conversion, since MBR boot loaders don't understand GPT, and so
// need to be replaced....
void MBRData::EmptyBootloader(void) {
int i;
for (i = 0; i < 440; i++)
code[i] = 0;
nulls = 0;
} // MBRData::EmptyBootloader
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
void MBRData::MakeProtectiveMBR(int clearBoot) {
@@ -523,6 +531,7 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
// Initialize variables
nulls = 0;
MBRSignature = MBR_SIGNATURE;
diskSignature = (uint32_t) rand();
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
@@ -561,7 +570,7 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
int bootable) {
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
// partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
partitions[num].firstSector[0] = UINT8_C(0);
partitions[num].firstSector[1] = UINT8_C(0);
partitions[num].firstSector[2] = UINT8_C(0);
@@ -576,9 +585,40 @@ void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
LBAtoCHS((uint64_t) start, partitions[num].firstSector);
LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector);
} // if (length > 0)
SetPartBootable(num, bootable);
} // if valid partition number
} // MBRData::MakePart()
// Set the partition's type code.
// Returns 1 if successful, 0 if not (invalid partition number)
int MBRData::SetPartType(int num, int type) {
int allOK = 1;
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
if (partitions[num].lengthLBA != UINT32_C(0)) {
partitions[num].partitionType = (uint8_t) type;
} else allOK = 0;
} else allOK = 0;
return allOK;
} // MBRData::SetPartType()
// Set (or remove) the partition's bootable flag. Setting it is the
// default; pass 0 as bootable to remove the flag.
// Returns 1 if successful, 0 if not (invalid partition number)
int MBRData::SetPartBootable(int num, int bootable) {
int allOK = 1;
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
if (partitions[num].lengthLBA != UINT32_C(0)) {
if (bootable == 0)
partitions[num].status = UINT8_C(0);
else
partitions[num].status = UINT8_C(0x80);
} else allOK = 0;
} else allOK = 0;
return allOK;
} // MBRData::SetPartBootable()
// Create a partition that fills the most available space. Returns
// 1 if partition was created, 0 otherwise. Intended for use in
// creating hybrid MBRs.
@@ -637,7 +677,7 @@ int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
start32 = (uint32_t) start64;
length32 = (uint32_t) length64;
for (i = 0; i < MAX_MBR_PARTS; i++) {
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA == length32) &&
(partitions[i].partitionType != 0xEE)) {
DeletePartition(i);
if (state == hybrid)
@@ -717,7 +757,7 @@ uint32_t MBRData::FindLastInFree(uint32_t start) {
uint32_t i;
if ((diskSize <= UINT32_MAX) && (diskSize > 0))
nearestStart = diskSize - 1;
nearestStart = (uint32_t) diskSize - 1;
else
nearestStart = UINT32_MAX - 1;
for (i = 0; i < 4; i++) {

3
mbr.h
View File

@@ -105,9 +105,12 @@ public:
// Functions to create, delete, or change partitions
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
void EmptyMBR(int clearBootloader = 1);
void EmptyBootloader(void);
void MakeProtectiveMBR(int clearBoot = 0);
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
int bootable = 0);
int SetPartType(int num, int type);
int SetPartBootable(int num, int bootable = 1);
int MakeBiggestPart(int i, int type); // Make partition filling most space
void DeletePartition(int i);
int DeleteByLocation(uint64_t start64, uint64_t length64);

View File

@@ -2,7 +2,7 @@
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <unistd.h>
//#include <unistd.h>
#include <stdlib.h>
#include <string>
#include "support.h"

View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH "SGDISK" "8" "0.6.3" "Roderick W. Smith" "GPT fdisk Manual"
.TH "SGDISK" "8" "0.6.4" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS"
@@ -60,14 +60,15 @@ attempt to convert the MBR or disklabel into GPT form. (BSD disklabels are
likely to have unusable first and/or final partitions because they overlap
with the GPT data structures, though.) GPT fdisk can identify, but not use
data in, Apple Partition Map (APM) disks, which are used on 680x0\- and
PowerPC\-based Macintoshes. If you specify any option that results in changes
to an MBR or BSD disklabel, \fBsgdisk\fR ignores those changes unless the
\fI\-g\fR (\fI\-\-mbrtogpt\fR) or \fI\-z\fR (\fI\-\-zap\fR) option is used.
If you use the \fI\-g\fR option, \fBsgdisk\fR replaces the MBR or disklabel
with a GPT. \fIThis action is potentially dangerous!\fR Your system may become
unbootable, and partition type codes may become corrupted if the disk uses
unrecognized type codes. Boot problems are particularly likely if you're
multi\-booting with any GPT\-unaware OS.
PowerPC\-based Macintoshes. If you specify any option that results in
changes to an MBR or BSD disklabel, \fBsgdisk\fR ignores those changes
unless the \fI\-g\fR (\fI\-\-mbrtogpt\fR), \fI\-z\fR (\fI\-\-zap\fR), or
\fI\-Z\fR (\fI\-\-zap\-all\fR) option is used. If you use the \fI\-g\fR
option, \fBsgdisk\fR replaces the MBR or disklabel with a GPT. \fIThis
action is potentially dangerous!\fR Your system may become unbootable, and
partition type codes may become corrupted if the disk uses unrecognized
type codes. Boot problems are particularly likely if you're multi\-booting
with any GPT\-unaware OS.
The MBR\-to\-GPT conversion will leave at least one gap in the partition
numbering if the original MBR used logical partitions. These gaps are
@@ -210,6 +211,17 @@ Convert an MBR or BSD disklabel disk to a GPT disk. As a safety measure, use of
this option is required on MBR or BSD disklabel disks if you intend to save your
changes, in order to prevent accidentally damaging such disks.
.TP
.B \-h, \-\-hybrid
Create a hybrid MBR. This option takes from one to three partition numbers,
separated by colons, as arguments. The created hybrid MBR places an EFI GPT
(type 0xEE) partition first in the table, followed by the partition(s) you
specify. Their type codes are based on the GPT fdisk type codes divided by
0x0100, which is usually correct for Windows partitions. If the
active/bootable flag should be set, you must do so in another program, such
as \fBfdisk\fR. The \fBgdisk\fR program offers additional hybrid MBR
creation options.
.TP
.B \-i, \-\-info=partnum
Show detailed partition information. The summary information produced by
@@ -241,6 +253,17 @@ adds code numbers sequentially, such as 0xa500 for a FreeBSD disklabel,
these two\-byte codes are unique to \fBgdisk\fR and \fBsgdisk\fR. This
option does not require you to specify a valid disk device filename.
.TP
.B \-m, \-\-gpttombr
Convert disk from GPT to MBR form. This option takes from one to four
partition numbers, separated by colons, as arguments. Their type codes are
based on the GPT fdisk type codes divided by 0x0100. If the active/bootable
flag should be set, you must do so in another program, such as \fBfdisk\fR.
The \fBgdisk\fR program offers additional MBR conversion options. It is not
possible to convert more than four partitions from GPT to MBR form or to
convert partitions that start above the 2TiB mark or that are larger than
2TiB.
.TP
.B \-n, \-\-new=partnum:start:end
Create a new partition. You enter a partition
@@ -274,6 +297,15 @@ Pretend to make specified changes. In\-memory GPT data structures are
altered according to other parameters, but changes are not written
to disk.
.TP
.B \-r, \-\-transpose
Swap two partitions' entries in the partition table. One or both partitions
may be empty, although swapping two empty partitions is pointless. For
instance, if partitions 1\-4 are defined, transposing 1 and 5 results in a
table with partitions numbered from 2\-5. Transposing partitions in this
way has no effect on their disk space allocation; it only alters their
order in the partition table.
.TP
.B \-s, \-\-sort
Sort partition entries. GPT partition numbers need not match the order of
@@ -317,14 +349,22 @@ specifying a device filename.
.TP
.B \-z, \-\-zap
Zap (destroy) the GPT data structures and exit. Use this option if you want to
repartition a GPT disk using \fBfdisk\fR or some other GPT\-unaware program.
You'll be given the choice of preserving the existing MBR, in case it's a
hybrid MBR with salvageable partitions or if you've already created new MBR
partitions and want to erase the remnants of your GPT partitions. \fIIf you've
already created new MBR partitions, it's conceivable that this option will
damage the first and/or last MBR partitions!\fR Such an event is unlikely, but
could occur if your new MBR partitions overlap the old GPT data structures.
Zap (destroy) the GPT data structures and then exit. Use this option if you
want to repartition a GPT disk using \fBfdisk\fR or some other GPT\-unaware
program. This option destroys only the GPT data structures; it leaves the
MBR intact. This makes it useful for wiping out GPT data structures after a
disk has been repartitioned for MBR using a GPT-unaware utility; however,
there's a risk that it will damage boot loaders or even the start of the
first or end of the last MBR partition. If you use it on a valid GPT disk,
the MBR will be left with an inappropriate EFI GPT (0xEE) partition
definition, which you can delete using another utility.
.TP
.B \-Z, \-\-zap\-all
Zap (destroy) the GPT and MBR data structures and then exit. This option
works much like \fI\-z\fR, but as it wipes the MBR as well as the GPT, it's
more suitable if you want to repartition a disk after using this option,
and completely unsuitable if you've already repartitioned the disk.
.TP
.B \-?, \-\-help
@@ -353,7 +393,7 @@ Non\-GPT disk detected and no \fI\-g\fR option
.B 4
An error prevented saving changes
.SH "BUGS"
As of January 2010 (version 0.6.0), \fBsgdisk\fR
As of February 2010 (version 0.6.4), \fBsgdisk\fR
should be considered beta software. Known bugs and limitations include:
.TP

View File

@@ -25,6 +25,8 @@ using namespace std;
uint64_t GetInt(char* Info, int itemNum);
string GetString(char* Info, int itemNum);
int BuildMBR(GPTData* theGPT, char* argument, int isHybrid);
int CountColons(char* argument);
int main(int argc, char *argv[]) {
GPTData theGPT;
@@ -35,8 +37,8 @@ int main(int argc, char *argv[]) {
uint32_t tableSize = 128;
uint64_t startSector, endSector;
char *device = NULL;
char *newPartInfo = NULL, *typeCode = NULL, *partName;
char *backupFile = NULL;
char *newPartInfo = NULL, *typeCode = NULL, *partName = NULL;
char *backupFile = NULL, *twoParts = NULL, *hybrids = NULL, *mbrParts;
PartType typeHelper;
poptContext poptCon;
@@ -50,20 +52,24 @@ int main(int argc, char *argv[]) {
{"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
{"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
{"mbrtogpt", 'g', POPT_ARG_NONE, NULL, 'g', "convert MBR to GPT", ""},
{"hybrid", 'h', POPT_ARG_STRING, &hybrids, 'h', "create hybrid MBR", "partnum[:partnum...]"},
{"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
{"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"},
{"list-types", 'L', POPT_ARG_NONE, NULL, 'L', "list known partition types", ""},
{"gpttombr", 'm', POPT_ARG_STRING, &mbrParts, 'm', "convert GPT to MBR", "partnum[:partnum...]"},
{"new", 'n', POPT_ARG_STRING, &newPartInfo, 'n', "create new partition", "partnum:start:end"},
{"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""},
{"print", 'p', POPT_ARG_NONE, NULL, 'p', "print partition table", ""},
{"pretend", 'P', POPT_ARG_NONE, NULL, 'P', "make changes in memory, but don't write them", ""},
{"transpose", 'r', POPT_ARG_STRING, &twoParts, 'r', "transpose two partitions", "partnum:partnum"},
{"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
{"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"},
{"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:hexcode"},
{"transform-bsd", 'T', POPT_ARG_INT, &bsdPartNum, 'T', "transform BSD disklabel partition to GPT", "partnum"},
{"verify", 'v', POPT_ARG_NONE, NULL, 'v', "check partition table integrity", ""},
{"version", 'V', POPT_ARG_NONE, NULL, 'V', "display version information", ""},
{"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT data structures", ""},
{"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT (but not MBR) data structures", ""},
{"zap-all", 'Z', POPT_ARG_NONE, NULL, 'Z', "zap (destroy) GPT and MBR data structures", ""},
POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }
};
@@ -150,6 +156,11 @@ int main(int argc, char *argv[]) {
saveData = 1;
saveNonGPT = 1;
break;
case 'h':
theGPT.JustLooking(0);
if (BuildMBR(&theGPT, hybrids, 1) == 1)
saveData = 1;
break;
case 'i':
theGPT.ShowPartDetails(infoPartNum - 1);
break;
@@ -165,6 +176,19 @@ int main(int argc, char *argv[]) {
break;
case 'L':
break;
case 'm':
theGPT.JustLooking(0);
if (BuildMBR(&theGPT, mbrParts, 0) == 1) {
if (!pretend) {
if (theGPT.SaveMBR())
theGPT.DestroyGPT();
else
cerr << "Problem saving MBR!\n";
} // if
saveNonGPT = 0;
saveData = 0;
} // if
break;
case 'n':
theGPT.JustLooking(0);
partNum = (int) GetInt(newPartInfo, 1) - 1;
@@ -190,6 +214,16 @@ int main(int argc, char *argv[]) {
case 'P':
pretend = 1;
break;
case 'r':
theGPT.JustLooking(0);
uint64_t p1, p2;
p1 = GetInt(twoParts, 1) - 1;
p2 = GetInt(twoParts, 2) - 1;
if (theGPT.SwapPartitions((uint32_t) p1, (uint32_t) p2) == 0) {
neverSaveData = 1;
cerr << "Cannot swap partitions " << p1 + 1 << " and " << p2 + 1 << "\n";
} else saveData = 1;
break;
case 's':
theGPT.JustLooking(0);
theGPT.SortGPT();
@@ -217,16 +251,26 @@ int main(int argc, char *argv[]) {
break;
case 'T':
theGPT.JustLooking(0);
theGPT.XFormDisklabel(bsdPartNum);
theGPT.XFormDisklabel(bsdPartNum - 1);
saveData = 1;
break;
case 'v':
theGPT.Verify();
break;
case 'z':
if (!pretend)
theGPT.DestroyGPT(-1);
if (!pretend) {
theGPT.DestroyGPT();
} // if
saveNonGPT = 0;
saveData = 0;
break;
case 'Z':
if (!pretend) {
theGPT.DestroyGPT();
theGPT.DestroyMBR();
} // if
saveNonGPT = 0;
saveData = 0;
break;
default:
cerr << "Unknown option (-" << opt << ")!\n";
@@ -287,3 +331,44 @@ string GetString(char* argument, int itemNum) {
return Info.substr(startPos, endPos - startPos + 1);
} // GetString()
// Create a hybrid or regular MBR from GPT data structures
int BuildMBR(GPTData* theGPT, char* argument, int isHybrid) {
int numParts, allOK = 1, i;
int gptParts[4], mbrTypes[4];
for (i = 0; i < 4; i++) {
gptParts[i] = MBR_EMPTY;
mbrTypes[i] = 0; // All 0s flags to use default type
} // for
if ((theGPT != NULL) && (argument != NULL) && ((isHybrid == 0) || (isHybrid == 1))) {
numParts = CountColons(argument) + 1;
if (numParts <= (4 - isHybrid)) {
if (isHybrid) {
gptParts[0] = MBR_EFI_GPT;
mbrTypes[0] = 0xEE;
} // if
for (i = 0; i < numParts; i++) {
gptParts[i + isHybrid] = GetInt(argument, i + 1) - 1;
} // for
if (theGPT->PartsToMBR(gptParts, mbrTypes) != numParts)
allOK = 0;
} else allOK = 0;
} else allOK = 0;
if (!allOK)
cerr << "Problem creating MBR!\n";
return allOK;
} // BuildMBR()
// Returns the number of colons in argument string
int CountColons(char* argument) {
int num = 0, i = 0;
if (argument != NULL) {
while (argument[i] != '\0') {
if (argument[i++] == ':')
num++;
} // while
} // if
return num;
} // CountColons()

View File

@@ -17,6 +17,7 @@
#include <sys/stat.h>
#include <string>
#include <iostream>
#include <sstream>
#include "support.h"
#include <sys/types.h>
@@ -166,10 +167,9 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string &
// form
string BytesToSI(uint64_t size) {
string units;
char theValue[99];
ostringstream theValue;
float sizeInSI;
theValue[0] = '\0';
sizeInSI = (float) size;
units = " bytes";
if (sizeInSI > 1024.0) {
@@ -192,12 +192,14 @@ string BytesToSI(uint64_t size) {
sizeInSI /= 1024.0;
units = " PiB";
} // if
theValue.setf(ios::fixed);
if (units == " bytes") { // in bytes, so no decimal point
sprintf(theValue, "%1.0f%s", sizeInSI, units.c_str());
theValue.precision(0);
} else {
sprintf(theValue, "%1.1f%s", sizeInSI, units.c_str());
theValue.precision(1);
} // if/else
return theValue;
theValue << sizeInSI << units;
return theValue.str();
} // BlocksToSI()
// Converts two consecutive characters in the input string into a

View File

@@ -2,14 +2,14 @@
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <unistd.h>
//#include <unistd.h>
#include <stdlib.h>
#include <string>
#ifndef __GPTSUPPORT
#define __GPTSUPPORT
#if defined (__FreeBSD__) || defined (__APPLE__)
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
// This used to use __DARWIN_UNIX03 rather than __APPLE__, but __APPLE__
// is more general. If the code fails to work on older versions of OS X/