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 - 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. 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 all: gdisk sgdisk
gdisk: $(LIB_OBJS) gdisk.o gdisk: $(LIB_OBJS) gdisk.o gpttext.o
$(CXX) $(LIB_OBJS) gdisk.o -L/opt/local/lib -L/usr/local/lib -luuid -o gdisk $(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/opt/local/lib -L/usr/local/lib -luuid -o gdisk
sgdisk: $(LIB_OBJS) sgdisk.o sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -luuid -lpopt -o sgdisk $(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 CC=/usr/bin/i686-pc-mingw32-gcc
CXX=/usr/bin/i586-mingw32msvc-g++ CXX=/usr/bin/i686-pc-mingw32-g++
STRIP=/usr/bin/i586-mingw32msvc-strip STRIP=/usr/bin/i686-pc-mingw32-strip
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g 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 -g
#CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -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. altogether.
I compiled gdisk.exe using MinGW (http://www.mingw.org), and in particular 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 its Linux-hosted cross-compiler. Under Ubuntu Linux, the Makefile.mingw
source code under more mainstream Windows compilers, or even on the file enables compilation of the software via MinGW. (Type "make -f
Windows-hosted MinGW variant. MinGW was designed for porting Unix Makefile.mingw" to compile the software.) If you try to compile using
applications to Windows, so it's entirely possible that it will work where another compiler or even using MinGW under Windows or another Linux
other compilers won't. variety, you may need to adjust the Makefile.mingw options.
Under Ubuntu Linux, the Makefile.mingw file enables compilation of the I've also attempted to compile the code with OpenWatcom 1.8 and Microsoft
software. (Type "make -f Makefile.mingw" to compile the software.) If you Visual C++ 2008 Express. My OpenWatcom attempts failed, mostly because the
try to compile using another compiler or even using MinGW under Windows or compiler can't yet handle iostream output on standard C++ strings.
another Linux variety, you may need to adjust the Makefile.mingw options. 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 If you modify GPT fdisk to get it to compile under another compiler, I
welcome submission of patches. welcome submission of patches.

View File

@@ -12,6 +12,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <iostream> #include <iostream>
#include <sstream>
#include "attributes.h" #include "attributes.h"
using namespace std; using namespace std;
@@ -20,13 +21,13 @@ using namespace std;
// data. // data.
Attributes::Attributes(void) { Attributes::Attributes(void) {
int i; int i;
char temp[ATR_NAME_SIZE]; ostringstream temp;
// Most bits are undefined, so start by giving them an // Most bits are undefined, so start by giving them an
// appropriate name // appropriate name
for (i = 1; i < NUM_ATR; i++) { for (i = 1; i < NUM_ATR; i++) {
sprintf(temp, "Undefined bit #%d", i); temp << "Undefined bit #" << i;
atNames[i] = temp; atNames[i] = temp.str();
} // for } // for
// Now reset those names that are defined.... // 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. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h> #include <stdint.h>
#include <unistd.h> //#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "support.h" #include "support.h"

12
bsd.cc
View File

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

5
bsd.h
View File

@@ -55,6 +55,9 @@ struct BSDRecord { // the partition table
}; };
// Full data in tweaked BSD format // 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 { class BSDData {
protected: protected:
// We only need a few items from the main BSD disklabel data structure.... // 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 sectorSize; // # of bytes per sector
uint32_t signature2; // the magic number (again) uint32_t signature2; // the magic number (again)
uint16_t numParts; // number of partitions in table 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.... // Above are basic BSD disklabel data; now add more stuff....
uint64_t labelFirstLBA; // first sector of BSD disklabel (partition or disk) 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. // so the file can be re-opened without specifying the filename.
void DiskIO::Close(void) { void DiskIO::Close(void) {
if (isOpen) if (isOpen)
close(fd); if (close(fd) < 0)
cerr << "Warning! Problem closing file!\n";
isOpen = 0; isOpen = 0;
openForWrite = 0; openForWrite = 0;
} // DiskIO::Close() } // DiskIO::Close()
@@ -117,7 +118,7 @@ int DiskIO::GetBlockSize(void) {
#ifdef __APPLE__ #ifdef __APPLE__
err = ioctl(fd, DKIOCGETBLOCKSIZE, &blockSize); err = ioctl(fd, DKIOCGETBLOCKSIZE, &blockSize);
#endif #endif
#ifdef __FreeBSD__ #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
err = ioctl(fd, DIOCGSECTORSIZE, &blockSize); err = ioctl(fd, DIOCGSECTORSIZE, &blockSize);
#endif #endif
#ifdef __linux__ #ifdef __linux__
@@ -161,7 +162,7 @@ void DiskIO::DiskSync(void) {
i = ioctl(fd, DKIOCSYNCHRONIZECACHE); i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
platformFound++; platformFound++;
#endif #endif
#ifdef __FreeBSD__ #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
sleep(2); sleep(2);
i = ioctl(fd, DIOCGFLUSH); i = ioctl(fd, DIOCGFLUSH);
cout << "Warning: The kernel may continue to use old or deleted partitions.\n" 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 // greatly since then to enable FreeBSD and MacOS support, as well as to
// return correct values for disk image files. // return correct values for disk image files.
uint64_t DiskIO::DiskSize(int *err) { 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 uint64_t sectors = 0; // size in sectors
off_t bytes = 0; // size in bytes off_t bytes = 0; // size in bytes
struct stat64 st; struct stat64 st;
@@ -317,13 +316,15 @@ uint64_t DiskIO::DiskSize(int *err) {
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, &sectors); *err = ioctl(fd, DKIOCGETBLOCKCOUNT, &sectors);
platformFound++; platformFound++;
#endif #endif
#ifdef __FreeBSD__ #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
*err = ioctl(fd, DIOCGMEDIASIZE, &bytes); *err = ioctl(fd, DIOCGMEDIASIZE, &bytes);
b = GetBlockSize(); long long b = GetBlockSize();
sectors = bytes / b; sectors = bytes / b;
platformFound++; platformFound++;
#endif #endif
#ifdef __linux__ #ifdef __linux__
long sz;
long long b;
*err = ioctl(fd, BLKGETSIZE, &sz); *err = ioctl(fd, BLKGETSIZE, &sz);
if (*err) { if (*err) {
sectors = sz = 0; sectors = sz = 0;

View File

@@ -19,7 +19,7 @@
#include <winioctl.h> #include <winioctl.h>
#define fstat64 fstat #define fstat64 fstat
#define stat64 stat #define stat64 stat
//#define S_IRGRP 0 #define S_IRGRP 0
#define S_IROTH 0 #define S_IROTH 0
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
@@ -93,6 +93,14 @@ int DiskIO::OpenForWrite(void) {
fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE, fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL); 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) { if (fd == INVALID_HANDLE_VALUE) {
CloseHandle(fd); CloseHandle(fd);
isOpen = 0; isOpen = 0;

View File

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

View File

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

10
gdisk.8
View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com) .\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License .\" 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" .SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS" .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 sizes also work fine. OSes may impose their own limits on the number of
partitions, though. 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 .TP
.B v .B v
Verify disk. This option is identical to the 'v' option in the main menu. Verify disk. This option is identical to the 'v' option in the main menu.

View File

@@ -9,24 +9,24 @@
//#include <iostream> //#include <iostream>
#include <stdio.h> #include <stdio.h>
#include <getopt.h> //#include <getopt.h>
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include "mbr.h" #include "mbr.h"
#include "gpt.h" #include "gpttext.h"
#include "support.h" #include "support.h"
// Function prototypes.... // Function prototypes....
void MainMenu(string filename, struct GPTData* theGPT); void MainMenu(string filename, GPTDataTextUI* theGPT);
void ShowCommands(void); void ShowCommands(void);
void ExpertsMenu(string filename, struct GPTData* theGPT); void ExpertsMenu(string filename, GPTDataTextUI* theGPT);
void ShowExpertCommands(void); void ShowExpertCommands(void);
void RecoveryMenu(string filename, struct GPTData* theGPT); void RecoveryMenu(string filename, GPTDataTextUI* theGPT);
void ShowRecoveryCommands(void); void ShowRecoveryCommands(void);
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
GPTData theGPT; GPTDataTextUI theGPT;
int doMore = 1; int doMore = 1;
char* device = NULL; char* device = NULL;
@@ -72,7 +72,7 @@ int main(int argc, char* argv[]) {
// Accept a command and execute it. Returns only when the user // Accept a command and execute it. Returns only when the user
// wants to exit (such as after a 'w' or 'q' command). // 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 command, line[255], buFile[255];
char* junk; char* junk;
int goOn = 1; int goOn = 1;
@@ -174,7 +174,7 @@ void ShowCommands(void) {
// Accept a recovery & transformation menu command. Returns only when the user // Accept a recovery & transformation menu command. Returns only when the user
// issues an exit command, such as 'w' or 'q'. // 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 command, line[255], buFile[255];
char* junk; char* junk;
uint32_t temp1; uint32_t temp1;
@@ -221,10 +221,11 @@ void RecoveryMenu(string filename, struct GPTData* theGPT) {
if (temp1 > 0) { if (temp1 > 0) {
cout << "Converted " << temp1 << " partitions. Finalize and exit? "; cout << "Converted " << temp1 << " partitions. Finalize and exit? ";
if (GetYN() == 'Y') { if (GetYN() == 'Y') {
if (theGPT->DestroyGPT(0) > 0) if (theGPT->DestroyGPT() > 0)
goOn = 0; goOn = 0;
} else { } else {
theGPT->MakeProtectiveMBR(); theGPT->MakeProtectiveMBR();
theGPT->WriteProtectiveMBR();
cout << "Note: New protective MBR created.\n"; cout << "Note: New protective MBR created.\n";
} // if/else } // if/else
} // if } // if
@@ -299,11 +300,10 @@ void ShowRecoveryCommands(void) {
// Accept an experts' menu command. Returns only after the user // Accept an experts' menu command. Returns only after the user
// selects an exit command, such as 'w' or 'q'. // 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 command, line[255];
char* junk; char* junk;
uint32_t pn; uint32_t pn, temp1, temp2;
uint32_t temp1, temp2;
int goOn = 1; int goOn = 1;
GUIDData aGUID; GUIDData aGUID;
@@ -359,10 +359,10 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
break; break;
case 'p': case 'P': case 'p': case 'P':
theGPT->DisplayGPTData(); theGPT->DisplayGPTData();
break; break;
case 'q': case 'Q': case 'q': case 'Q':
goOn = 0; goOn = 0;
break; break;
case 'r': case 'R': case 'r': case 'R':
RecoveryMenu(filename, theGPT); RecoveryMenu(filename, theGPT);
goOn = 0; goOn = 0;
@@ -370,6 +370,9 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
case 's': case 'S': case 's': case 'S':
theGPT->ResizePartitionTable(); theGPT->ResizePartitionTable();
break; break;
case 't': case 'T':
theGPT->SwapPartitions();
break;
case 'v': case 'V': case 'v': case 'V':
theGPT->Verify(); theGPT->Verify();
break; break;
@@ -379,7 +382,7 @@ void ExpertsMenu(string filename, struct GPTData* theGPT) {
} // if } // if
break; break;
case 'z': case 'Z': case 'z': case 'Z':
if (theGPT->DestroyGPT() == 1) { if (theGPT->DestroyGPTwPrompt() == 1) {
goOn = 0; goOn = 0;
} }
break; break;
@@ -405,6 +408,7 @@ void ShowExpertCommands(void) {
cout << "q\tquit without saving changes\n"; cout << "q\tquit without saving changes\n";
cout << "r\trecovery and transformation options (experts only)\n"; cout << "r\trecovery and transformation options (experts only)\n";
cout << "s\tresize partition table\n"; cout << "s\tresize partition table\n";
cout << "t\ttranspose two partition table entries\n";
cout << "v\tverify disk\n"; cout << "v\tverify disk\n";
cout << "w\twrite table to disk and exit\n"; cout << "w\twrite table to disk and exit\n";
cout << "z\tzap (destroy) GPT data structures 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 #ifndef __GPTSTRUCTS
#define __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; using namespace std;
@@ -83,7 +89,7 @@ public:
// Basic necessary functions.... // Basic necessary functions....
GPTData(void); GPTData(void);
GPTData(string deviceFilename); GPTData(string deviceFilename);
~GPTData(void); virtual ~GPTData(void);
// Verify (or update) data integrity // Verify (or update) data integrity
int Verify(void); int Verify(void);
@@ -98,6 +104,7 @@ public:
// Load or save data from/to disk // Load or save data from/to disk
int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);} int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);}
int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);}
void PartitionScan(void); void PartitionScan(void);
int LoadPartitions(const string & deviceFilename); int LoadPartitions(const string & deviceFilename);
int ForceLoadGPTData(void); int ForceLoadGPTData(void);
@@ -106,32 +113,24 @@ public:
int SaveGPTData(int quiet = 0); int SaveGPTData(int quiet = 0);
int SaveGPTBackup(const string & filename); int SaveGPTBackup(const string & filename);
int LoadGPTBackup(const string & filename); int LoadGPTBackup(const string & filename);
int SaveMBR(void);
int DestroyGPT(void);
int DestroyMBR(void);
// Display data.... // Display data....
void ShowAPMState(void); void ShowAPMState(void);
void ShowGPTState(void); void ShowGPTState(void);
void DisplayGPTData(void); void DisplayGPTData(void);
void DisplayMBRData(void) {protectiveMBR.DisplayMBRData();} void DisplayMBRData(void) {protectiveMBR.DisplayMBRData();}
void ShowDetails(void);
void ShowPartDetails(uint32_t partNum); void ShowPartDetails(uint32_t partNum);
// Request information from the user (& possibly do something with it) // Convert between GPT and other formats
uint32_t GetPartNum(void); virtual WhichToUse UseWhichPartitions(void);
void ResizePartitionTable(void); void XFormPartitions(void);
void CreatePartition(void); virtual int XFormDisklabel(uint32_t partNum);
void DeletePartition(void); int XFormDisklabel(BSDData* disklabel);
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);
int OnePartToMBR(uint32_t gptPart, int mbrPart); // add one partition to MBR. Returns 1 if successful 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 int PartsToMBR(const int *gptParts, const int *mbrTypes);
void MakeHybrid(void);
// Adjust GPT structures WITHOUT user interaction... // Adjust GPT structures WITHOUT user interaction...
int SetGPTSize(uint32_t numEntries); int SetGPTSize(uint32_t numEntries);
@@ -139,6 +138,8 @@ public:
int DeletePartition(uint32_t partNum); int DeletePartition(uint32_t partNum);
uint32_t CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector); uint32_t CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector);
void SortGPT(void); void SortGPT(void);
void QuickSortGPT(int start, int finish);
int SwapPartitions(uint32_t partNum1, uint32_t partNum2);
int ClearGPTData(void); int ClearGPTData(void);
void MoveSecondHeaderToEnd(); void MoveSecondHeaderToEnd();
int SetName(uint32_t partNum, const string & theName = ""); int SetName(uint32_t partNum, const string & theName = "");
@@ -150,6 +151,7 @@ public:
// Return data about the GPT structures.... // Return data about the GPT structures....
int GetPartRange(uint32_t* low, uint32_t* high); int GetPartRange(uint32_t* low, uint32_t* high);
int FindFirstFreePart(void);
uint32_t GetNumParts(void) {return mainHeader.numParts;} uint32_t GetNumParts(void) {return mainHeader.numParts;}
uint64_t GetMainHeaderLBA(void) {return mainHeader.currentLBA;} uint64_t GetMainHeaderLBA(void) {return mainHeader.currentLBA;}
uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;} uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}

View File

@@ -66,6 +66,11 @@ string GPTPart::GetDescription(void) {
return theName; return theName;
} // GPTPart::GetDescription() } // 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 // 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 // name *IF* the current name is the generic one for the current partition
// type. // type.
@@ -139,6 +144,7 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
if (firstLBA != 0) { if (firstLBA != 0) {
sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1)); sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1));
cout.fill(' ');
cout.width(4); cout.width(4);
cout << partNum + 1 << " "; cout << partNum + 1 << " ";
cout.width(14); cout.width(14);
@@ -256,36 +262,3 @@ void GPTPart::ChangeType(void) {
SetDefaultDescription(); SetDefaultDescription();
} // if } // if
} // GPTPart::ChangeType() } // 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 GetLengthLBA(void);
uint64_t GetAttributes(void) {return attributes;} uint64_t GetAttributes(void) {return attributes;}
string GetDescription(void); string GetDescription(void);
int IsUsed(void);
// Simple data assignment: // Simple data assignment:
void SetType(PartType t); void SetType(PartType t);
@@ -83,7 +84,4 @@ class GPTPart {
void ChangeType(void); // Change the type code void ChangeType(void); // Change the type code
}; // struct GPTPart }; // struct GPTPart
// A support function that doesn't quite belong in the class....
void QuickSortGPT(GPTPart* partitions, int start, int finish);
#endif #endif

58
mbr.cc
View File

@@ -10,7 +10,7 @@
#define __STDC_CONSTANT_MACROS #define __STDC_CONSTANT_MACROS
#include <stdio.h> #include <stdio.h>
#include <unistd.h> //#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <fcntl.h> #include <fcntl.h>
@@ -273,7 +273,7 @@ int MBRData::WriteMBRData(void) {
int allOK = 1; int allOK = 1;
if (myDisk != NULL) { if (myDisk != NULL) {
if (myDisk->OpenForWrite(device) != 0) { if (myDisk->OpenForWrite() != 0) {
allOK = WriteMBRData(myDisk); allOK = WriteMBRData(myDisk);
} else { } else {
allOK = 0; allOK = 0;
@@ -493,10 +493,7 @@ void MBRData::EmptyMBR(int clearBootloader) {
// 2-byte nulls area only if requested to do so. (This is the // 2-byte nulls area only if requested to do so. (This is the
// default.) // default.)
if (clearBootloader == 1) { if (clearBootloader == 1) {
for (i = 0; i < 440; i++) EmptyBootloader();
code[i] = 0;
diskSignature = (uint32_t) rand();
nulls = 0;
} // if } // if
// Blank out the partitions // Blank out the partitions
@@ -515,6 +512,17 @@ void MBRData::EmptyMBR(int clearBootloader) {
MBRSignature = MBR_SIGNATURE; MBRSignature = MBR_SIGNATURE;
} // MBRData::EmptyMBR() } // 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. // Create a protective MBR. Clears the boot loader area if clearBoot > 0.
void MBRData::MakeProtectiveMBR(int clearBoot) { void MBRData::MakeProtectiveMBR(int clearBoot) {
@@ -523,6 +531,7 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
// Initialize variables // Initialize variables
nulls = 0; nulls = 0;
MBRSignature = MBR_SIGNATURE; MBRSignature = MBR_SIGNATURE;
diskSignature = (uint32_t) rand();
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable 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, void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
int bootable) { int bootable) {
if ((num >= 0) && (num < MAX_MBR_PARTS)) { 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[0] = UINT8_C(0);
partitions[num].firstSector[1] = UINT8_C(0); partitions[num].firstSector[1] = UINT8_C(0);
partitions[num].firstSector[2] = 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, partitions[num].firstSector);
LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector); LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector);
} // if (length > 0) } // if (length > 0)
SetPartBootable(num, bootable);
} // if valid partition number } // if valid partition number
} // MBRData::MakePart() } // 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 // Create a partition that fills the most available space. Returns
// 1 if partition was created, 0 otherwise. Intended for use in // 1 if partition was created, 0 otherwise. Intended for use in
// creating hybrid MBRs. // creating hybrid MBRs.
@@ -637,7 +677,7 @@ int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
start32 = (uint32_t) start64; start32 = (uint32_t) start64;
length32 = (uint32_t) length64; length32 = (uint32_t) length64;
for (i = 0; i < MAX_MBR_PARTS; i++) { 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)) { (partitions[i].partitionType != 0xEE)) {
DeletePartition(i); DeletePartition(i);
if (state == hybrid) if (state == hybrid)
@@ -717,7 +757,7 @@ uint32_t MBRData::FindLastInFree(uint32_t start) {
uint32_t i; uint32_t i;
if ((diskSize <= UINT32_MAX) && (diskSize > 0)) if ((diskSize <= UINT32_MAX) && (diskSize > 0))
nearestStart = diskSize - 1; nearestStart = (uint32_t) diskSize - 1;
else else
nearestStart = UINT32_MAX - 1; nearestStart = UINT32_MAX - 1;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {

3
mbr.h
View File

@@ -105,9 +105,12 @@ public:
// Functions to create, delete, or change partitions // Functions to create, delete, or change partitions
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact // Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
void EmptyMBR(int clearBootloader = 1); void EmptyMBR(int clearBootloader = 1);
void EmptyBootloader(void);
void MakeProtectiveMBR(int clearBoot = 0); void MakeProtectiveMBR(int clearBoot = 0);
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07, void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
int bootable = 0); 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 int MakeBiggestPart(int i, int type); // Make partition filling most space
void DeletePartition(int i); void DeletePartition(int i);
int DeleteByLocation(uint64_t start64, uint64_t length64); 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. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h> #include <stdint.h>
#include <unistd.h> //#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include "support.h" #include "support.h"

View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com) .\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License .\" 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" .SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS" .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 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 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 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 PowerPC\-based Macintoshes. If you specify any option that results in
to an MBR or BSD disklabel, \fBsgdisk\fR ignores those changes unless the changes to an MBR or BSD disklabel, \fBsgdisk\fR ignores those changes
\fI\-g\fR (\fI\-\-mbrtogpt\fR) or \fI\-z\fR (\fI\-\-zap\fR) option is used. unless the \fI\-g\fR (\fI\-\-mbrtogpt\fR), \fI\-z\fR (\fI\-\-zap\fR), or
If you use the \fI\-g\fR option, \fBsgdisk\fR replaces the MBR or disklabel \fI\-Z\fR (\fI\-\-zap\-all\fR) option is used. If you use the \fI\-g\fR
with a GPT. \fIThis action is potentially dangerous!\fR Your system may become option, \fBsgdisk\fR replaces the MBR or disklabel with a GPT. \fIThis
unbootable, and partition type codes may become corrupted if the disk uses action is potentially dangerous!\fR Your system may become unbootable, and
unrecognized type codes. Boot problems are particularly likely if you're partition type codes may become corrupted if the disk uses unrecognized
multi\-booting with any GPT\-unaware OS. 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 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 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 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. 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 .TP
.B \-i, \-\-info=partnum .B \-i, \-\-info=partnum
Show detailed partition information. The summary information produced by 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 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. 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 .TP
.B \-n, \-\-new=partnum:start:end .B \-n, \-\-new=partnum:start:end
Create a new partition. You enter a partition 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 altered according to other parameters, but changes are not written
to disk. 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 .TP
.B \-s, \-\-sort .B \-s, \-\-sort
Sort partition entries. GPT partition numbers need not match the order of Sort partition entries. GPT partition numbers need not match the order of
@@ -317,14 +349,22 @@ specifying a device filename.
.TP .TP
.B \-z, \-\-zap .B \-z, \-\-zap
Zap (destroy) the GPT data structures and exit. Use this option if you want to Zap (destroy) the GPT data structures and then exit. Use this option if you
repartition a GPT disk using \fBfdisk\fR or some other GPT\-unaware program. want to repartition a GPT disk using \fBfdisk\fR or some other GPT\-unaware
You'll be given the choice of preserving the existing MBR, in case it's a program. This option destroys only the GPT data structures; it leaves the
hybrid MBR with salvageable partitions or if you've already created new MBR MBR intact. This makes it useful for wiping out GPT data structures after a
partitions and want to erase the remnants of your GPT partitions. \fIIf you've disk has been repartitioned for MBR using a GPT-unaware utility; however,
already created new MBR partitions, it's conceivable that this option will there's a risk that it will damage boot loaders or even the start of the
damage the first and/or last MBR partitions!\fR Such an event is unlikely, but first or end of the last MBR partition. If you use it on a valid GPT disk,
could occur if your new MBR partitions overlap the old GPT data structures. 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 .TP
.B \-?, \-\-help .B \-?, \-\-help
@@ -353,7 +393,7 @@ Non\-GPT disk detected and no \fI\-g\fR option
.B 4 .B 4
An error prevented saving changes An error prevented saving changes
.SH "BUGS" .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: should be considered beta software. Known bugs and limitations include:
.TP .TP

View File

@@ -25,6 +25,8 @@ using namespace std;
uint64_t GetInt(char* Info, int itemNum); uint64_t GetInt(char* Info, int itemNum);
string GetString(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[]) { int main(int argc, char *argv[]) {
GPTData theGPT; GPTData theGPT;
@@ -35,8 +37,8 @@ int main(int argc, char *argv[]) {
uint32_t tableSize = 128; uint32_t tableSize = 128;
uint64_t startSector, endSector; uint64_t startSector, endSector;
char *device = NULL; char *device = NULL;
char *newPartInfo = NULL, *typeCode = NULL, *partName; char *newPartInfo = NULL, *typeCode = NULL, *partName = NULL;
char *backupFile = NULL; char *backupFile = NULL, *twoParts = NULL, *hybrids = NULL, *mbrParts;
PartType typeHelper; PartType typeHelper;
poptContext poptCon; 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", ""}, {"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", ""}, {"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", ""}, {"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"}, {"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"}, {"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", ""}, {"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"}, {"new", 'n', POPT_ARG_STRING, &newPartInfo, 'n', "create new partition", "partnum:start:end"},
{"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""}, {"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""},
{"print", 'p', POPT_ARG_NONE, NULL, 'p', "print 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", ""}, {"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", ""}, {"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
{"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"}, {"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"}, {"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"}, {"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", ""}, {"verify", 'v', POPT_ARG_NONE, NULL, 'v', "check partition table integrity", ""},
{"version", 'V', POPT_ARG_NONE, NULL, 'V', "display version information", ""}, {"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 } POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }
}; };
@@ -150,6 +156,11 @@ int main(int argc, char *argv[]) {
saveData = 1; saveData = 1;
saveNonGPT = 1; saveNonGPT = 1;
break; break;
case 'h':
theGPT.JustLooking(0);
if (BuildMBR(&theGPT, hybrids, 1) == 1)
saveData = 1;
break;
case 'i': case 'i':
theGPT.ShowPartDetails(infoPartNum - 1); theGPT.ShowPartDetails(infoPartNum - 1);
break; break;
@@ -165,6 +176,19 @@ int main(int argc, char *argv[]) {
break; break;
case 'L': case 'L':
break; 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': case 'n':
theGPT.JustLooking(0); theGPT.JustLooking(0);
partNum = (int) GetInt(newPartInfo, 1) - 1; partNum = (int) GetInt(newPartInfo, 1) - 1;
@@ -190,6 +214,16 @@ int main(int argc, char *argv[]) {
case 'P': case 'P':
pretend = 1; pretend = 1;
break; 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': case 's':
theGPT.JustLooking(0); theGPT.JustLooking(0);
theGPT.SortGPT(); theGPT.SortGPT();
@@ -217,16 +251,26 @@ int main(int argc, char *argv[]) {
break; break;
case 'T': case 'T':
theGPT.JustLooking(0); theGPT.JustLooking(0);
theGPT.XFormDisklabel(bsdPartNum); theGPT.XFormDisklabel(bsdPartNum - 1);
saveData = 1; saveData = 1;
break; break;
case 'v': case 'v':
theGPT.Verify(); theGPT.Verify();
break; break;
case 'z': case 'z':
if (!pretend) if (!pretend) {
theGPT.DestroyGPT(-1); theGPT.DestroyGPT();
} // if
saveNonGPT = 0; saveNonGPT = 0;
saveData = 0;
break;
case 'Z':
if (!pretend) {
theGPT.DestroyGPT();
theGPT.DestroyMBR();
} // if
saveNonGPT = 0;
saveData = 0;
break; break;
default: default:
cerr << "Unknown option (-" << opt << ")!\n"; cerr << "Unknown option (-" << opt << ")!\n";
@@ -287,3 +331,44 @@ string GetString(char* argument, int itemNum) {
return Info.substr(startPos, endPos - startPos + 1); return Info.substr(startPos, endPos - startPos + 1);
} // GetString() } // 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 <sys/stat.h>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sstream>
#include "support.h" #include "support.h"
#include <sys/types.h> #include <sys/types.h>
@@ -166,10 +167,9 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, const string &
// form // form
string BytesToSI(uint64_t size) { string BytesToSI(uint64_t size) {
string units; string units;
char theValue[99]; ostringstream theValue;
float sizeInSI; float sizeInSI;
theValue[0] = '\0';
sizeInSI = (float) size; sizeInSI = (float) size;
units = " bytes"; units = " bytes";
if (sizeInSI > 1024.0) { if (sizeInSI > 1024.0) {
@@ -192,12 +192,14 @@ string BytesToSI(uint64_t size) {
sizeInSI /= 1024.0; sizeInSI /= 1024.0;
units = " PiB"; units = " PiB";
} // if } // if
theValue.setf(ios::fixed);
if (units == " bytes") { // in bytes, so no decimal point if (units == " bytes") { // in bytes, so no decimal point
sprintf(theValue, "%1.0f%s", sizeInSI, units.c_str()); theValue.precision(0);
} else { } else {
sprintf(theValue, "%1.1f%s", sizeInSI, units.c_str()); theValue.precision(1);
} // if/else } // if/else
return theValue; theValue << sizeInSI << units;
return theValue.str();
} // BlocksToSI() } // BlocksToSI()
// Converts two consecutive characters in the input string into a // 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. */ under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h> #include <stdint.h>
#include <unistd.h> //#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#ifndef __GPTSUPPORT #ifndef __GPTSUPPORT
#define __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 // Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
// This used to use __DARWIN_UNIX03 rather than __APPLE__, but __APPLE__ // 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/ // is more general. If the code fails to work on older versions of OS X/