Version 0.6.4
This commit is contained in:
47
CHANGELOG
47
CHANGELOG
@@ -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.
|
||||||
|
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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....
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
10
bsd.cc
10
bsd.cc
@@ -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,6 +37,7 @@ BSDData::BSDData(void) {
|
|||||||
} // default constructor
|
} // default constructor
|
||||||
|
|
||||||
BSDData::~BSDData(void) {
|
BSDData::~BSDData(void) {
|
||||||
|
if (partitions != NULL)
|
||||||
delete[] partitions;
|
delete[] partitions;
|
||||||
} // destructor
|
} // destructor
|
||||||
|
|
||||||
@@ -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
5
bsd.h
@@ -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)
|
||||||
|
|||||||
@@ -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, §ors);
|
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, §ors);
|
||||||
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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
2
diskio.h
2
diskio.h
@@ -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
10
gdisk.8
@@ -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.
|
||||||
|
|||||||
30
gdisk.cc
30
gdisk.cc
@@ -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;
|
||||||
|
|
||||||
@@ -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";
|
||||||
|
|||||||
718
gpt.cc
718
gpt.cc
@@ -10,7 +10,6 @@
|
|||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -99,7 +98,6 @@ int GPTData::Verify(void) {
|
|||||||
int problems = 0;
|
int problems = 0;
|
||||||
uint32_t i, numSegments;
|
uint32_t i, numSegments;
|
||||||
uint64_t totalFree, largestSegment;
|
uint64_t totalFree, largestSegment;
|
||||||
char siTotal[255], siLargest[255];
|
|
||||||
|
|
||||||
// First, check for CRC errors in the GPT data....
|
// First, check for CRC errors in the GPT data....
|
||||||
if (!mainCrcOk) {
|
if (!mainCrcOk) {
|
||||||
@@ -231,8 +229,6 @@ int GPTData::Verify(void) {
|
|||||||
// problems could affect the results
|
// problems could affect the results
|
||||||
if (problems == 0) {
|
if (problems == 0) {
|
||||||
totalFree = FindFreeBlocks(&numSegments, &largestSegment);
|
totalFree = FindFreeBlocks(&numSegments, &largestSegment);
|
||||||
strcpy(siTotal, BytesToSI(totalFree * (uint64_t) blockSize).c_str());
|
|
||||||
strcpy(siLargest, BytesToSI(largestSegment * (uint64_t) blockSize).c_str());
|
|
||||||
cout << "No problems found. " << totalFree << " free sectors ("
|
cout << "No problems found. " << totalFree << " free sectors ("
|
||||||
<< BytesToSI(totalFree * (uint64_t) blockSize) << ") available in "
|
<< BytesToSI(totalFree * (uint64_t) blockSize) << ") available in "
|
||||||
<< numSegments << "\nsegments, the largest of which is "
|
<< numSegments << "\nsegments, the largest of which is "
|
||||||
@@ -386,10 +382,6 @@ void GPTData::RecomputeCRCs(void) {
|
|||||||
ReverseHeaderBytes(&mainHeader);
|
ReverseHeaderBytes(&mainHeader);
|
||||||
ReverseHeaderBytes(&secondHeader);
|
ReverseHeaderBytes(&secondHeader);
|
||||||
} // if
|
} // if
|
||||||
/* if ((littleEndian = IsLittleEndian()) == 0) {
|
|
||||||
ReverseBytes(&trueNumParts, 4);
|
|
||||||
ReverseBytes(&hSize, 4);
|
|
||||||
} // if */
|
|
||||||
|
|
||||||
// Compute CRC of partition tables & store in main and secondary headers
|
// Compute CRC of partition tables & store in main and secondary headers
|
||||||
crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
|
crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
|
||||||
@@ -566,10 +558,10 @@ void GPTData::PartitionScan(void) {
|
|||||||
|
|
||||||
// Read GPT data from a disk.
|
// Read GPT data from a disk.
|
||||||
int GPTData::LoadPartitions(const string & deviceFilename) {
|
int GPTData::LoadPartitions(const string & deviceFilename) {
|
||||||
|
BSDData bsdDisklabel;
|
||||||
int err, allOK = 1;
|
int err, allOK = 1;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
uint64_t firstBlock, lastBlock;
|
uint64_t firstBlock, lastBlock;
|
||||||
BSDData bsdDisklabel;
|
|
||||||
MBRValidity mbrState;
|
MBRValidity mbrState;
|
||||||
|
|
||||||
// First, do a test to see if writing will be possible later....
|
// First, do a test to see if writing will be possible later....
|
||||||
@@ -577,7 +569,7 @@ int GPTData::LoadPartitions(const string & deviceFilename) {
|
|||||||
if ((err == 0) && (!justLooking)) {
|
if ((err == 0) && (!justLooking)) {
|
||||||
cout << "\aNOTE: Write test failed with error number " << errno
|
cout << "\aNOTE: Write test failed with error number " << errno
|
||||||
<< ". It will be impossible to save\nchanges to this disk's partition table!\n";
|
<< ". It will be impossible to save\nchanges to this disk's partition table!\n";
|
||||||
#ifdef __FreeBSD__
|
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
|
||||||
cout << "You may be able to enable writes by exiting this program, typing\n"
|
cout << "You may be able to enable writes by exiting this program, typing\n"
|
||||||
<< "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n"
|
<< "'sysctl kern.geom.debugflags=16' at a shell prompt, and re-running this\n"
|
||||||
<< "program.\n";
|
<< "program.\n";
|
||||||
@@ -604,7 +596,7 @@ int GPTData::LoadPartitions(const string & deviceFilename) {
|
|||||||
// bsdDisklabel.DisplayBSDData();
|
// bsdDisklabel.DisplayBSDData();
|
||||||
ClearGPTData();
|
ClearGPTData();
|
||||||
protectiveMBR.MakeProtectiveMBR(1); // clear boot area (option 1)
|
protectiveMBR.MakeProtectiveMBR(1); // clear boot area (option 1)
|
||||||
XFormDisklabel(&bsdDisklabel, 0);
|
XFormDisklabel(&bsdDisklabel);
|
||||||
break;
|
break;
|
||||||
case use_gpt:
|
case use_gpt:
|
||||||
mbrState = protectiveMBR.GetValidity();
|
mbrState = protectiveMBR.GetValidity();
|
||||||
@@ -655,12 +647,12 @@ int GPTData::ForceLoadGPTData(void) {
|
|||||||
if (mainCrcOk && (mainHeader.backupLBA < diskSize)) {
|
if (mainCrcOk && (mainHeader.backupLBA < diskSize)) {
|
||||||
allOK = LoadHeader(&secondHeader, myDisk, mainHeader.backupLBA, &secondCrcOk) && allOK;
|
allOK = LoadHeader(&secondHeader, myDisk, mainHeader.backupLBA, &secondCrcOk) && allOK;
|
||||||
} else {
|
} else {
|
||||||
if (mainHeader.backupLBA >= diskSize)
|
allOK = LoadHeader(&secondHeader, myDisk, diskSize - UINT64_C(1), &secondCrcOk) && allOK;
|
||||||
|
if (mainCrcOk && (mainHeader.backupLBA >= diskSize))
|
||||||
cout << "Warning! Disk size is smaller than the main header indicates! Loading\n"
|
cout << "Warning! Disk size is smaller than the main header indicates! Loading\n"
|
||||||
<< "secondary header from the last sector of the disk! You should use 'v' to\n"
|
<< "secondary header from the last sector of the disk! You should use 'v' to\n"
|
||||||
<< "verify disk integrity, and perhaps options on the experts' menu to repair\n"
|
<< "verify disk integrity, and perhaps options on the experts' menu to repair\n"
|
||||||
<< "the disk.\n";
|
<< "the disk.\n";
|
||||||
allOK = LoadHeader(&secondHeader, myDisk, diskSize - UINT64_C(1), &secondCrcOk) && allOK;
|
|
||||||
} // if/else
|
} // if/else
|
||||||
if (!allOK)
|
if (!allOK)
|
||||||
state = gpt_invalid;
|
state = gpt_invalid;
|
||||||
@@ -850,7 +842,6 @@ int GPTData::CheckTable(struct GPTHeader *header) {
|
|||||||
int GPTData::SaveGPTData(int quiet) {
|
int GPTData::SaveGPTData(int quiet) {
|
||||||
int allOK = 1, littleEndian;
|
int allOK = 1, littleEndian;
|
||||||
char answer;
|
char answer;
|
||||||
// uint64_t secondTable;
|
|
||||||
uint32_t numParts;
|
uint32_t numParts;
|
||||||
|
|
||||||
littleEndian = IsLittleEndian();
|
littleEndian = IsLittleEndian();
|
||||||
@@ -1129,6 +1120,91 @@ int GPTData::LoadGPTBackup(const string & filename) {
|
|||||||
return allOK;
|
return allOK;
|
||||||
} // GPTData::LoadGPTBackup()
|
} // GPTData::LoadGPTBackup()
|
||||||
|
|
||||||
|
int GPTData::SaveMBR(void) {
|
||||||
|
return protectiveMBR.WriteMBRData();
|
||||||
|
} // GPTData::SaveMBR()
|
||||||
|
|
||||||
|
// This function destroys the on-disk GPT structures, but NOT the on-disk
|
||||||
|
// MBR.
|
||||||
|
// Returns 1 if the operation succeeds, 0 if not.
|
||||||
|
int GPTData::DestroyGPT(void) {
|
||||||
|
int i, sum, tableSize, allOK = 1;
|
||||||
|
uint8_t blankSector[512];
|
||||||
|
uint8_t* emptyTable;
|
||||||
|
|
||||||
|
for (i = 0; i < 512; i++) {
|
||||||
|
blankSector[i] = 0;
|
||||||
|
} // for
|
||||||
|
|
||||||
|
if (myDisk.OpenForWrite()) {
|
||||||
|
if (!myDisk.Seek(mainHeader.currentLBA))
|
||||||
|
allOK = 0;
|
||||||
|
if (myDisk.Write(blankSector, 512) != 512) { // blank it out
|
||||||
|
cerr << "Warning! GPT main header not overwritten! Error is " << errno << "\n";
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
if (!myDisk.Seek(mainHeader.partitionEntriesLBA))
|
||||||
|
allOK = 0;
|
||||||
|
tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
|
||||||
|
emptyTable = new uint8_t[tableSize];
|
||||||
|
for (i = 0; i < tableSize; i++)
|
||||||
|
emptyTable[i] = 0;
|
||||||
|
if (allOK) {
|
||||||
|
sum = myDisk.Write(emptyTable, tableSize);
|
||||||
|
if (sum != tableSize) {
|
||||||
|
cerr << "Warning! GPT main partition table not overwritten! Error is " << errno << "\n";
|
||||||
|
allOK = 0;
|
||||||
|
} // if write failed
|
||||||
|
} // if
|
||||||
|
if (!myDisk.Seek(secondHeader.partitionEntriesLBA))
|
||||||
|
allOK = 0;
|
||||||
|
if (allOK) {
|
||||||
|
sum = myDisk.Write(emptyTable, tableSize);
|
||||||
|
if (sum != tableSize) {
|
||||||
|
cerr << "Warning! GPT backup partition table not overwritten! Error is "
|
||||||
|
<< errno << "\n";
|
||||||
|
allOK = 0;
|
||||||
|
} // if wrong size written
|
||||||
|
} // if
|
||||||
|
if (!myDisk.Seek(secondHeader.currentLBA))
|
||||||
|
allOK = 0;
|
||||||
|
if (allOK) {
|
||||||
|
if (myDisk.Write(blankSector, 512) != 512) { // blank it out
|
||||||
|
cerr << "Warning! GPT backup header not overwritten! Error is " << errno << "\n";
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
} // if
|
||||||
|
myDisk.DiskSync();
|
||||||
|
myDisk.Close();
|
||||||
|
cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n"
|
||||||
|
<< "other utilities.\n";
|
||||||
|
delete[] emptyTable;
|
||||||
|
} else {
|
||||||
|
cerr << "Problem opening " << device << " for writing! Program will now terminate.\n";
|
||||||
|
} // if/else (fd != -1)
|
||||||
|
return (allOK);
|
||||||
|
} // GPTDataTextUI::DestroyGPT()
|
||||||
|
|
||||||
|
// Wipe MBR data from the disk (zero it out completely)
|
||||||
|
// Returns 1 on success, 0 on failure.
|
||||||
|
int GPTData::DestroyMBR(void) {
|
||||||
|
int allOK = 1, i;
|
||||||
|
uint8_t blankSector[512];
|
||||||
|
|
||||||
|
for (i = 0; i < 512; i++)
|
||||||
|
blankSector[i] = 0;
|
||||||
|
|
||||||
|
if (myDisk.OpenForWrite()) {
|
||||||
|
if (myDisk.Seek(0)) {
|
||||||
|
if (myDisk.Write(blankSector, 512) != 512)
|
||||||
|
allOK = 0;
|
||||||
|
} else allOK = 0;
|
||||||
|
} else allOK = 0;
|
||||||
|
if (!allOK)
|
||||||
|
cerr << "Warning! MBR not overwritten! Error is " << errno << "!\n";
|
||||||
|
return allOK;
|
||||||
|
} // GPTData::DestroyMBR(void)
|
||||||
|
|
||||||
// Tell user whether Apple Partition Map (APM) was discovered....
|
// Tell user whether Apple Partition Map (APM) was discovered....
|
||||||
void GPTData::ShowAPMState(void) {
|
void GPTData::ShowAPMState(void) {
|
||||||
if (apmFound)
|
if (apmFound)
|
||||||
@@ -1176,20 +1252,6 @@ void GPTData::DisplayGPTData(void) {
|
|||||||
} // for
|
} // for
|
||||||
} // GPTData::DisplayGPTData()
|
} // GPTData::DisplayGPTData()
|
||||||
|
|
||||||
// Get partition number from user and then call ShowPartDetails(partNum)
|
|
||||||
// to show its detailed information
|
|
||||||
void GPTData::ShowDetails(void) {
|
|
||||||
int partNum;
|
|
||||||
uint32_t low, high;
|
|
||||||
|
|
||||||
if (GetPartRange(&low, &high) > 0) {
|
|
||||||
partNum = GetPartNum();
|
|
||||||
ShowPartDetails(partNum);
|
|
||||||
} else {
|
|
||||||
cout << "No partitions\n";
|
|
||||||
} // if/else
|
|
||||||
} // GPTData::ShowDetails()
|
|
||||||
|
|
||||||
// Show detailed information on the specified partition
|
// Show detailed information on the specified partition
|
||||||
void GPTData::ShowPartDetails(uint32_t partNum) {
|
void GPTData::ShowPartDetails(uint32_t partNum) {
|
||||||
if (partitions[partNum].GetFirstLBA() != 0) {
|
if (partitions[partNum].GetFirstLBA() != 0) {
|
||||||
@@ -1199,220 +1261,6 @@ void GPTData::ShowPartDetails(uint32_t partNum) {
|
|||||||
} // if
|
} // if
|
||||||
} // GPTData::ShowPartDetails()
|
} // GPTData::ShowPartDetails()
|
||||||
|
|
||||||
/*********************************************************************
|
|
||||||
* *
|
|
||||||
* Begin functions that obtain information from the users, and often *
|
|
||||||
* do something with that information (call other functions) *
|
|
||||||
* *
|
|
||||||
*********************************************************************/
|
|
||||||
|
|
||||||
// Prompts user for partition number and returns the result.
|
|
||||||
uint32_t GPTData::GetPartNum(void) {
|
|
||||||
uint32_t partNum;
|
|
||||||
uint32_t low, high;
|
|
||||||
char prompt[255];
|
|
||||||
|
|
||||||
if (GetPartRange(&low, &high) > 0) {
|
|
||||||
sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
|
|
||||||
partNum = GetNumber(low + 1, high + 1, low, prompt);
|
|
||||||
} else partNum = 1;
|
|
||||||
return (partNum - 1);
|
|
||||||
} // GPTData::GetPartNum()
|
|
||||||
|
|
||||||
// What it says: Resize the partition table. (Default is 128 entries.)
|
|
||||||
void GPTData::ResizePartitionTable(void) {
|
|
||||||
int newSize;
|
|
||||||
char prompt[255];
|
|
||||||
uint32_t curLow, curHigh;
|
|
||||||
|
|
||||||
cout << "Current partition table size is " << mainHeader.numParts << ".\n";
|
|
||||||
GetPartRange(&curLow, &curHigh);
|
|
||||||
curHigh++; // since GetPartRange() returns numbers starting from 0...
|
|
||||||
// There's no point in having fewer than four partitions....
|
|
||||||
if (curHigh < 4)
|
|
||||||
curHigh = 4;
|
|
||||||
sprintf(prompt, "Enter new size (%d up, default %d): ", (int) curHigh,
|
|
||||||
(int) NUM_GPT_ENTRIES);
|
|
||||||
newSize = GetNumber(4, 65535, 128, prompt);
|
|
||||||
if (newSize < 128) {
|
|
||||||
cout << "Caution: The partition table size should officially be 16KB or larger,\n"
|
|
||||||
<< "which works out to 128 entries. In practice, smaller tables seem to\n"
|
|
||||||
<< "work with most OSes, but this practice is risky. I'm proceeding with\n"
|
|
||||||
<< "the resize, but you may want to reconsider this action and undo it.\n\n";
|
|
||||||
} // if
|
|
||||||
SetGPTSize(newSize);
|
|
||||||
} // GPTData::ResizePartitionTable()
|
|
||||||
|
|
||||||
// Interactively create a partition
|
|
||||||
void GPTData::CreatePartition(void) {
|
|
||||||
uint64_t firstBlock, firstInLargest, lastBlock, sector;
|
|
||||||
uint32_t firstFreePart = 0;
|
|
||||||
char prompt[255];
|
|
||||||
int partNum;
|
|
||||||
|
|
||||||
// Find first free partition...
|
|
||||||
while (partitions[firstFreePart].GetFirstLBA() != 0) {
|
|
||||||
firstFreePart++;
|
|
||||||
} // while
|
|
||||||
|
|
||||||
if (((firstBlock = FindFirstAvailable()) != 0) &&
|
|
||||||
(firstFreePart < mainHeader.numParts)) {
|
|
||||||
lastBlock = FindLastAvailable();
|
|
||||||
firstInLargest = FindFirstInLargest();
|
|
||||||
|
|
||||||
// Get partition number....
|
|
||||||
do {
|
|
||||||
sprintf(prompt, "Partition number (%d-%d, default %d): ", firstFreePart + 1,
|
|
||||||
mainHeader.numParts, firstFreePart + 1);
|
|
||||||
partNum = GetNumber(firstFreePart + 1, mainHeader.numParts,
|
|
||||||
firstFreePart + 1, prompt) - 1;
|
|
||||||
if (partitions[partNum].GetFirstLBA() != 0)
|
|
||||||
cout << "partition " << partNum + 1 << " is in use.\n";
|
|
||||||
} while (partitions[partNum].GetFirstLBA() != 0);
|
|
||||||
|
|
||||||
// Get first block for new partition...
|
|
||||||
sprintf(prompt, "First sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
|
|
||||||
(unsigned long long) firstBlock, (unsigned long long) lastBlock,
|
|
||||||
(unsigned long long) firstInLargest);
|
|
||||||
do {
|
|
||||||
sector = GetSectorNum(firstBlock, lastBlock, firstInLargest, prompt);
|
|
||||||
} while (IsFree(sector) == 0);
|
|
||||||
Align(§or); // Align sector to correct multiple
|
|
||||||
firstBlock = sector;
|
|
||||||
|
|
||||||
// Get last block for new partitions...
|
|
||||||
lastBlock = FindLastInFree(firstBlock);
|
|
||||||
sprintf(prompt, "Last sector (%llu-%llu, default = %llu) or {+-}size{KMGT}: ",
|
|
||||||
(unsigned long long) firstBlock, (unsigned long long) lastBlock,
|
|
||||||
(unsigned long long) lastBlock);
|
|
||||||
do {
|
|
||||||
sector = GetSectorNum(firstBlock, lastBlock, lastBlock, prompt);
|
|
||||||
} while (IsFree(sector) == 0);
|
|
||||||
lastBlock = sector;
|
|
||||||
|
|
||||||
firstFreePart = CreatePartition(partNum, firstBlock, lastBlock);
|
|
||||||
partitions[partNum].ChangeType();
|
|
||||||
partitions[partNum].SetDefaultDescription();
|
|
||||||
} else {
|
|
||||||
cout << "No free sectors available\n";
|
|
||||||
} // if/else
|
|
||||||
} // GPTData::CreatePartition()
|
|
||||||
|
|
||||||
// Interactively delete a partition (duh!)
|
|
||||||
void GPTData::DeletePartition(void) {
|
|
||||||
int partNum;
|
|
||||||
uint32_t low, high;
|
|
||||||
char prompt[255];
|
|
||||||
|
|
||||||
if (GetPartRange(&low, &high) > 0) {
|
|
||||||
sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
|
|
||||||
partNum = GetNumber(low + 1, high + 1, low, prompt);
|
|
||||||
DeletePartition(partNum - 1);
|
|
||||||
} else {
|
|
||||||
cout << "No partitions\n";
|
|
||||||
} // if/else
|
|
||||||
} // GPTData::DeletePartition()
|
|
||||||
|
|
||||||
// Prompt user for a partition number, then change its type code
|
|
||||||
// using ChangeGPTType(struct GPTPartition*) function.
|
|
||||||
void GPTData::ChangePartType(void) {
|
|
||||||
int partNum;
|
|
||||||
uint32_t low, high;
|
|
||||||
|
|
||||||
if (GetPartRange(&low, &high) > 0) {
|
|
||||||
partNum = GetPartNum();
|
|
||||||
partitions[partNum].ChangeType();
|
|
||||||
} else {
|
|
||||||
cout << "No partitions\n";
|
|
||||||
} // if/else
|
|
||||||
} // GPTData::ChangePartType()
|
|
||||||
|
|
||||||
// Partition attributes seem to be rarely used, but I want a way to
|
|
||||||
// adjust them for completeness....
|
|
||||||
void GPTData::SetAttributes(uint32_t partNum) {
|
|
||||||
Attributes theAttr;
|
|
||||||
|
|
||||||
theAttr.SetAttributes(partitions[partNum].GetAttributes());
|
|
||||||
theAttr.DisplayAttributes();
|
|
||||||
theAttr.ChangeAttributes();
|
|
||||||
partitions[partNum].SetAttributes(theAttr.GetAttributes());
|
|
||||||
} // GPTData::SetAttributes()
|
|
||||||
|
|
||||||
// This function destroys the on-disk GPT structures. Returns 1 if the
|
|
||||||
// user confirms destruction, 0 if the user aborts.
|
|
||||||
// If prompt == 0, don't ask user about proceeding and do NOT wipe out
|
|
||||||
// MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.)
|
|
||||||
// If prompt == -1, don't ask user about proceeding and DO wipe out
|
|
||||||
// MBR.
|
|
||||||
int GPTData::DestroyGPT(int prompt) {
|
|
||||||
int i, sum, tableSize;
|
|
||||||
uint8_t blankSector[512], goOn = 'Y', blank = 'N';
|
|
||||||
uint8_t* emptyTable;
|
|
||||||
|
|
||||||
for (i = 0; i < 512; i++) {
|
|
||||||
blankSector[i] = 0;
|
|
||||||
} // for
|
|
||||||
|
|
||||||
if (((apmFound) || (bsdFound)) && (prompt > 0)) {
|
|
||||||
cout << "WARNING: APM or BSD disklabel structures detected! This operation could\n"
|
|
||||||
<< "damage any APM or BSD partitions on this disk!\n";
|
|
||||||
} // if APM or BSD
|
|
||||||
if (prompt > 0) {
|
|
||||||
cout << "\a\aAbout to wipe out GPT on " << device << ". Proceed? ";
|
|
||||||
goOn = GetYN();
|
|
||||||
} // if
|
|
||||||
if (goOn == 'Y') {
|
|
||||||
if (myDisk.OpenForWrite(device)) {
|
|
||||||
myDisk.Seek(mainHeader.currentLBA); // seek to GPT header
|
|
||||||
if (myDisk.Write(blankSector, 512) != 512) { // blank it out
|
|
||||||
cerr << "Warning! GPT main header not overwritten! Error is " << errno << "\n";
|
|
||||||
} // if
|
|
||||||
myDisk.Seek(mainHeader.partitionEntriesLBA); // seek to partition table
|
|
||||||
tableSize = mainHeader.numParts * mainHeader.sizeOfPartitionEntries;
|
|
||||||
emptyTable = new uint8_t[tableSize];
|
|
||||||
for (i = 0; i < tableSize; i++)
|
|
||||||
emptyTable[i] = 0;
|
|
||||||
sum = myDisk.Write(emptyTable, tableSize);
|
|
||||||
if (sum != tableSize)
|
|
||||||
cerr << "Warning! GPT main partition table not overwritten! Error is " << errno << "\n";
|
|
||||||
myDisk.Seek(secondHeader.partitionEntriesLBA); // seek to partition table
|
|
||||||
sum = myDisk.Write(emptyTable, tableSize);
|
|
||||||
if (sum != tableSize)
|
|
||||||
cerr << "Warning! GPT backup partition table not overwritten! Error is " << errno << "\n";
|
|
||||||
myDisk.Seek(secondHeader.currentLBA); // seek to GPT header
|
|
||||||
if (myDisk.Write(blankSector, 512) != 512) { // blank it out
|
|
||||||
cerr << "Warning! GPT backup header not overwritten! Error is " << errno << "\n";
|
|
||||||
} // if
|
|
||||||
if (prompt > 0) {
|
|
||||||
cout << "Blank out MBR? ";
|
|
||||||
blank = GetYN();
|
|
||||||
} // if
|
|
||||||
// Note on below: Touch the MBR only if the user wants it completely
|
|
||||||
// blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote
|
|
||||||
// the MBR, but this could wipe out a valid MBR that the program
|
|
||||||
// had subsequently discarded (say, if it conflicted with older GPT
|
|
||||||
// structures).
|
|
||||||
if ((blank == 'Y') || (prompt < 0)) {
|
|
||||||
myDisk.Seek(0);
|
|
||||||
if (myDisk.Write(blankSector, 512) != 512) { // blank it out
|
|
||||||
cerr << "Warning! MBR not overwritten! Error is " << errno << "!\n";
|
|
||||||
} // if
|
|
||||||
} else {
|
|
||||||
cout << "MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n"
|
|
||||||
<< "with fdisk or another tool.\n";
|
|
||||||
} // if/else
|
|
||||||
myDisk.DiskSync();
|
|
||||||
myDisk.Close();
|
|
||||||
cout << "GPT data structures destroyed! You may now partition the disk using fdisk or\n"
|
|
||||||
<< "other utilities. Program will now terminate.\n";
|
|
||||||
delete[] emptyTable;
|
|
||||||
} else {
|
|
||||||
cerr << "Problem opening " << device << " for writing! Program will now terminate.\n";
|
|
||||||
} // if/else (fd != -1)
|
|
||||||
} // if (goOn == 'Y')
|
|
||||||
return (goOn == 'Y');
|
|
||||||
} // GPTData::DestroyGPT()
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* *
|
* *
|
||||||
* Partition table transformation functions (MBR or BSD disklabel to GPT) *
|
* Partition table transformation functions (MBR or BSD disklabel to GPT) *
|
||||||
@@ -1420,13 +1268,14 @@ int GPTData::DestroyGPT(int prompt) {
|
|||||||
* *
|
* *
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
// Examines the MBR & GPT data, and perhaps asks the user questions, to
|
// Examines the MBR & GPT data to determine which set of data to use: the
|
||||||
// determine which set of data to use: the MBR (use_mbr), the GPT (use_gpt),
|
// MBR (use_mbr), the GPT (use_gpt), the BSD disklabel (use_bsd), or create
|
||||||
// or create a new set of partitions (use_new)
|
// a new set of partitions (use_new). A return value of use_abort indicates
|
||||||
|
// that this function couldn't determine what to do. Overriding functions
|
||||||
|
// in derived classes may ask users questions in such cases.
|
||||||
WhichToUse GPTData::UseWhichPartitions(void) {
|
WhichToUse GPTData::UseWhichPartitions(void) {
|
||||||
WhichToUse which = use_new;
|
WhichToUse which = use_new;
|
||||||
MBRValidity mbrState;
|
MBRValidity mbrState;
|
||||||
int answer;
|
|
||||||
|
|
||||||
mbrState = protectiveMBR.GetValidity();
|
mbrState = protectiveMBR.GetValidity();
|
||||||
|
|
||||||
@@ -1470,49 +1319,20 @@ WhichToUse GPTData::UseWhichPartitions(void) {
|
|||||||
which = use_gpt;
|
which = use_gpt;
|
||||||
} // if
|
} // if
|
||||||
if ((state == gpt_valid) && (mbrState == mbr)) {
|
if ((state == gpt_valid) && (mbrState == mbr)) {
|
||||||
if (!beQuiet) {
|
which = use_abort;
|
||||||
cout << "Found valid MBR and GPT. Which do you want to use?\n";
|
|
||||||
answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: ");
|
|
||||||
if (answer == 1) {
|
|
||||||
which = use_mbr;
|
|
||||||
} else if (answer == 2) {
|
|
||||||
which = use_gpt;
|
|
||||||
cout << "Using GPT and creating fresh protective MBR.\n";
|
|
||||||
} else which = use_new;
|
|
||||||
} else which = use_abort;
|
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// Nasty decisions here -- GPT is present, but corrupt (bad CRCs or other
|
|
||||||
// problems)
|
|
||||||
if (state == gpt_corrupt) {
|
if (state == gpt_corrupt) {
|
||||||
if (beQuiet) {
|
if (mbrState == gpt) {
|
||||||
which = use_abort;
|
|
||||||
} else {
|
|
||||||
if ((mbrState == mbr) || (mbrState == hybrid)) {
|
|
||||||
cout << "Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n"
|
|
||||||
<< "GPT MAY permit recovery of GPT data.)\n";
|
|
||||||
answer = GetNumber(1, 3, 2, " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: ");
|
|
||||||
if (answer == 1) {
|
|
||||||
which = use_mbr;
|
|
||||||
} else if (answer == 2) {
|
|
||||||
which = use_gpt;
|
|
||||||
} else which = use_new;
|
|
||||||
} else if (mbrState == invalid) {
|
|
||||||
cout << "Found invalid MBR and corrupt GPT. What do you want to do? (Using the\n"
|
|
||||||
<< "GPT MAY permit recovery of GPT data.)\n";
|
|
||||||
answer = GetNumber(1, 2, 1, " 1 - GPT\n 2 - Create blank GPT\n\nYour answer: ");
|
|
||||||
if (answer == 1) {
|
|
||||||
which = use_gpt;
|
|
||||||
} else which = use_new;
|
|
||||||
} else { // corrupt GPT, MBR indicates it's a GPT disk....
|
|
||||||
cout << "\a\a****************************************************************************\n"
|
cout << "\a\a****************************************************************************\n"
|
||||||
<< "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n"
|
<< "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n"
|
||||||
<< "verification and recovery are STRONGLY recommended.\n"
|
<< "verification and recovery are STRONGLY recommended.\n"
|
||||||
<< "****************************************************************************\n";
|
<< "****************************************************************************\n";
|
||||||
which = use_gpt;
|
which = use_gpt;
|
||||||
} // if/else/else
|
} else {
|
||||||
} // else (beQuiet)
|
which = use_abort;
|
||||||
} // if (corrupt GPT)
|
} // if/else MBR says disk is GPT
|
||||||
|
} // if GPT corrupt
|
||||||
|
|
||||||
if (which == use_new)
|
if (which == use_new)
|
||||||
cout << "Creating new GPT entries.\n";
|
cout << "Creating new GPT entries.\n";
|
||||||
@@ -1520,13 +1340,14 @@ WhichToUse GPTData::UseWhichPartitions(void) {
|
|||||||
return which;
|
return which;
|
||||||
} // UseWhichPartitions()
|
} // UseWhichPartitions()
|
||||||
|
|
||||||
// Convert MBR partition table into GPT form
|
// Convert MBR partition table into GPT form.
|
||||||
int GPTData::XFormPartitions(void) {
|
void GPTData::XFormPartitions(void) {
|
||||||
int i, numToConvert;
|
int i, numToConvert;
|
||||||
uint8_t origType;
|
uint8_t origType;
|
||||||
|
|
||||||
// Clear out old data & prepare basics....
|
// Clear out old data & prepare basics....
|
||||||
ClearGPTData();
|
ClearGPTData();
|
||||||
|
protectiveMBR.EmptyBootloader();
|
||||||
|
|
||||||
// Convert the smaller of the # of GPT or MBR partitions
|
// Convert the smaller of the # of GPT or MBR partitions
|
||||||
if (mainHeader.numParts > (MAX_MBR_PARTS))
|
if (mainHeader.numParts > (MAX_MBR_PARTS))
|
||||||
@@ -1549,35 +1370,23 @@ int GPTData::XFormPartitions(void) {
|
|||||||
// Record that all original CRCs were OK so as not to raise flags
|
// Record that all original CRCs were OK so as not to raise flags
|
||||||
// when doing a disk verification
|
// when doing a disk verification
|
||||||
mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1;
|
mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1;
|
||||||
|
|
||||||
return (1);
|
|
||||||
} // GPTData::XFormPartitions()
|
} // GPTData::XFormPartitions()
|
||||||
|
|
||||||
// Transforms BSD disklabel on the specified partition (numbered from 0).
|
// Transforms BSD disklabel on the specified partition (numbered from 0).
|
||||||
// If an invalid partition number is given, the program prompts for one.
|
// If an invalid partition number is given, the program does nothing.
|
||||||
// (Default for i is -1; called without an option, it therefore prompts.)
|
|
||||||
// Returns the number of new partitions created.
|
// Returns the number of new partitions created.
|
||||||
int GPTData::XFormDisklabel(int i) {
|
int GPTData::XFormDisklabel(uint32_t partNum) {
|
||||||
uint32_t low, high, partNum, startPart;
|
uint32_t low, high;
|
||||||
uint16_t hexCode;
|
|
||||||
int goOn = 1, numDone = 0;
|
int goOn = 1, numDone = 0;
|
||||||
BSDData disklabel;
|
BSDData disklabel;
|
||||||
|
|
||||||
if (GetPartRange(&low, &high) != 0) {
|
if (GetPartRange(&low, &high) == 0) {
|
||||||
if ((i < (int) low) || (i > (int) high))
|
goOn = 0;
|
||||||
partNum = GetPartNum();
|
cout << "No partitions!\n";
|
||||||
else
|
} // if
|
||||||
partNum = (uint32_t) i;
|
if (partNum > high) {
|
||||||
|
goOn = 0;
|
||||||
// Find the partition after the last used one
|
cout << "Specified partition is invalid!\n";
|
||||||
startPart = high + 1;
|
|
||||||
|
|
||||||
// Now see if the specified partition has a BSD type code....
|
|
||||||
hexCode = partitions[partNum].GetHexType();
|
|
||||||
if ((hexCode != 0xa500) && (hexCode != 0xa900)) {
|
|
||||||
cout << "Specified partition doesn't have a disklabel partition type "
|
|
||||||
<< "code.\nContinue anyway? ";
|
|
||||||
goOn = (GetYN() == 'Y');
|
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// If all is OK, read the disklabel and convert it.
|
// If all is OK, read the disklabel and convert it.
|
||||||
@@ -1585,9 +1394,9 @@ int GPTData::XFormDisklabel(int i) {
|
|||||||
goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(),
|
goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(),
|
||||||
partitions[partNum].GetLastLBA());
|
partitions[partNum].GetLastLBA());
|
||||||
if ((goOn) && (disklabel.IsDisklabel())) {
|
if ((goOn) && (disklabel.IsDisklabel())) {
|
||||||
numDone = XFormDisklabel(&disklabel, startPart);
|
numDone = XFormDisklabel(&disklabel);
|
||||||
if (numDone == 1)
|
if (numDone == 1)
|
||||||
cout << "Converted " << numDone << " BSD partition.\n";
|
cout << "Converted 1 BSD partition.\n";
|
||||||
else
|
else
|
||||||
cout << "Converted " << numDone << " BSD partitions.\n";
|
cout << "Converted " << numDone << " BSD partitions.\n";
|
||||||
} else {
|
} else {
|
||||||
@@ -1597,23 +1406,24 @@ int GPTData::XFormDisklabel(int i) {
|
|||||||
if (numDone > 0) { // converted partitions; delete carrier
|
if (numDone > 0) { // converted partitions; delete carrier
|
||||||
partitions[partNum].BlankPartition();
|
partitions[partNum].BlankPartition();
|
||||||
} // if
|
} // if
|
||||||
} else {
|
|
||||||
cout << "No partitions\n";
|
|
||||||
} // if/else
|
|
||||||
return numDone;
|
return numDone;
|
||||||
} // GPTData::XFormDisklable(int i)
|
} // GPTData::XFormDisklable(int i)
|
||||||
|
|
||||||
// Transform the partitions on an already-loaded BSD disklabel...
|
// Transform the partitions on an already-loaded BSD disklabel...
|
||||||
int GPTData::XFormDisklabel(BSDData* disklabel, uint32_t startPart) {
|
int GPTData::XFormDisklabel(BSDData* disklabel) {
|
||||||
int i, numDone = 0;
|
int i, partNum = 0, numDone = 0;
|
||||||
|
|
||||||
if ((disklabel->IsDisklabel()) && (startPart >= 0) &&
|
if (disklabel->IsDisklabel()) {
|
||||||
(startPart < mainHeader.numParts)) {
|
|
||||||
for (i = 0; i < disklabel->GetNumParts(); i++) {
|
for (i = 0; i < disklabel->GetNumParts(); i++) {
|
||||||
partitions[i + startPart] = disklabel->AsGPT(i);
|
partNum = FindFirstFreePart();
|
||||||
if (partitions[i + startPart].GetFirstLBA() != UINT64_C(0))
|
if (partNum >= 0) {
|
||||||
|
partitions[partNum] = disklabel->AsGPT(i);
|
||||||
|
if (partitions[partNum].IsUsed())
|
||||||
numDone++;
|
numDone++;
|
||||||
|
} // if
|
||||||
} // for
|
} // for
|
||||||
|
if (partNum == -1)
|
||||||
|
cerr << "Warning! Too many partitions to convert!\n";
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// Record that all original CRCs were OK so as not to raise flags
|
// Record that all original CRCs were OK so as not to raise flags
|
||||||
@@ -1623,16 +1433,13 @@ int GPTData::XFormDisklabel(BSDData* disklabel, uint32_t startPart) {
|
|||||||
return numDone;
|
return numDone;
|
||||||
} // GPTData::XFormDisklabel(BSDData* disklabel)
|
} // GPTData::XFormDisklabel(BSDData* disklabel)
|
||||||
|
|
||||||
// Add one GPT partition to MBR. Used by XFormToMBR() and MakeHybrid()
|
// Add one GPT partition to MBR. Used by PartsToMBR() functions. Created
|
||||||
// functions. Returns 1 if operation was successful.
|
// partition has the active/bootable flag UNset and uses the GPT fdisk
|
||||||
|
// type code divided by 0x0100 as the MBR type code.
|
||||||
|
// Returns 1 if operation was 100% successful, 0 if there were ANY
|
||||||
|
// problems.
|
||||||
int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
||||||
int allOK = 1, typeCode, bootable;
|
int allOK = 1;
|
||||||
uint64_t length;
|
|
||||||
char line[255];
|
|
||||||
char* junk;
|
|
||||||
|
|
||||||
cout.setf(ios::uppercase);
|
|
||||||
cout.fill('0');
|
|
||||||
|
|
||||||
if ((mbrPart < 0) || (mbrPart > 3)) {
|
if ((mbrPart < 0) || (mbrPart > 3)) {
|
||||||
cout << "MBR partition " << mbrPart + 1 << " is out of range; omitting it.\n";
|
cout << "MBR partition " << mbrPart + 1 << " is out of range; omitting it.\n";
|
||||||
@@ -1651,156 +1458,60 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
|||||||
if (partitions[gptPart].GetLastLBA() > UINT32_MAX) {
|
if (partitions[gptPart].GetLastLBA() > UINT32_MAX) {
|
||||||
cout << "Caution: Partition end point past 32-bit pointer boundary;"
|
cout << "Caution: Partition end point past 32-bit pointer boundary;"
|
||||||
<< " some OSes may\nreact strangely.\n";
|
<< " some OSes may\nreact strangely.\n";
|
||||||
} // if partition ends past 32-bit (usually 2TiB) boundary
|
} // if
|
||||||
do {
|
|
||||||
cout << "Enter an MBR hex code (default " << hex;
|
|
||||||
cout.width(2);
|
|
||||||
cout << partitions[gptPart].GetHexType() / 0x0100 << "): ";
|
|
||||||
junk = fgets(line, 255, stdin);
|
|
||||||
if (line[0] == '\n')
|
|
||||||
typeCode = partitions[gptPart].GetHexType() / 256;
|
|
||||||
else
|
|
||||||
sscanf(line, "%x", &typeCode);
|
|
||||||
} while ((typeCode <= 0) || (typeCode > 255));
|
|
||||||
cout << "Set the bootable flag? ";
|
|
||||||
bootable = (GetYN() == 'Y');
|
|
||||||
length = partitions[gptPart].GetLengthLBA();
|
|
||||||
protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(),
|
protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(),
|
||||||
(uint32_t) length, typeCode, bootable);
|
(uint32_t) partitions[gptPart].GetLengthLBA(),
|
||||||
|
partitions[gptPart].GetHexType() / 256, 0);
|
||||||
} else { // partition out of range
|
} else { // partition out of range
|
||||||
|
if (allOK) // Display only if "else" triggered by out-of-bounds condition
|
||||||
cout << "Partition " << gptPart + 1 << " begins beyond the 32-bit pointer limit of MBR "
|
cout << "Partition " << gptPart + 1 << " begins beyond the 32-bit pointer limit of MBR "
|
||||||
<< "partitions, or is\n too big; omitting it.\n";
|
<< "partitions, or is\n too big; omitting it.\n";
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if/else
|
} // if/else
|
||||||
cout.fill(' ');
|
|
||||||
return allOK;
|
return allOK;
|
||||||
} // GPTData::OnePartToMBR()
|
} // GPTData::OnePartToMBR()
|
||||||
|
|
||||||
// Convert the GPT to MBR form. This function is necessarily limited; it
|
// Convert up to four partitions to MBR form and return the number done.
|
||||||
// handles at most four partitions and creates layouts that ignore CHS
|
// Partitions are specified in an array of GPT partition numbers,
|
||||||
// geometries. Returns the number of converted partitions; if this value
|
// with an associated array of partition type codes. Both must be
|
||||||
// is over 0, the calling function should call DestroyGPT() to destroy
|
// at least four elements in size (longer is OK, but will be ignored).
|
||||||
// the GPT data, and then exit.
|
// A partition number of MBR_EFI_GPT means to place an EFI GPT
|
||||||
int GPTData::XFormToMBR(void) {
|
// protective partition in that location in the table (the associated
|
||||||
char line[255];
|
// mbrType[] should be 0xEE), and MBR_EMPTY means not to create a
|
||||||
char* junk;
|
// partition in that table position. If the mbrType[] entry for a
|
||||||
int j, numParts, numConverted = 0;
|
// partition is 0, a default entry is used, based on the GPT
|
||||||
uint32_t i, partNums[4];
|
// partition type code.
|
||||||
|
// Returns the number of partitions converted, NOT counting EFI GPT
|
||||||
|
// protective partitions.
|
||||||
|
int GPTData::PartsToMBR(const int *gptParts, const int *mbrTypes) {
|
||||||
|
int i, numConverted = 0;
|
||||||
|
|
||||||
// Get the numbers of up to four partitions to add to the
|
if ((gptParts != NULL) && (mbrTypes != NULL)) {
|
||||||
// hybrid MBR....
|
protectiveMBR.EmptyMBR();
|
||||||
numParts = CountParts();
|
|
||||||
cout << "Counted " << numParts << " partitions.\n";
|
|
||||||
|
|
||||||
// Prepare the MBR for conversion (empty it of existing partitions).
|
|
||||||
protectiveMBR.EmptyMBR(0);
|
|
||||||
protectiveMBR.SetDiskSize(diskSize);
|
protectiveMBR.SetDiskSize(diskSize);
|
||||||
|
// Do two passes, one to get "real" partitions and
|
||||||
if (numParts > 4) { // Over four partitions; engage in triage
|
// the next to create EFI GPT protective partition(s)
|
||||||
cout << "Type from one to four GPT partition numbers, separated by spaces, to be\n"
|
|
||||||
<< "used in the MBR, in sequence: ";
|
|
||||||
junk = fgets(line, 255, stdin);
|
|
||||||
numParts = sscanf(line, "%d %d %d %d", &partNums[0], &partNums[1],
|
|
||||||
&partNums[2], &partNums[3]);
|
|
||||||
} else { // Four or fewer partitions; convert them all
|
|
||||||
i = j = 0;
|
|
||||||
while ((j < numParts) && (i < mainHeader.numParts)) {
|
|
||||||
if (partitions[i].GetFirstLBA() > 0) { // if GPT part. is defined
|
|
||||||
partNums[j++] = ++i; // flag it for conversion
|
|
||||||
} else i++;
|
|
||||||
} // while
|
|
||||||
} // if/else
|
|
||||||
|
|
||||||
for (i = 0; i < (uint32_t) numParts; i++) {
|
|
||||||
j = partNums[i] - 1;
|
|
||||||
cout << "\nCreating entry for partition #" << j + 1 << "\n";
|
|
||||||
numConverted += OnePartToMBR(j, i);
|
|
||||||
} // for
|
|
||||||
cout << "MBR writing returned " << protectiveMBR.WriteMBRData(&myDisk) << "\n";
|
|
||||||
return numConverted;
|
|
||||||
} // GPTData::XFormToMBR()
|
|
||||||
|
|
||||||
// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with
|
|
||||||
// OSes that don't understand GPT.
|
|
||||||
void GPTData::MakeHybrid(void) {
|
|
||||||
uint32_t partNums[3];
|
|
||||||
char line[255];
|
|
||||||
char* junk;
|
|
||||||
int numParts, numConverted = 0, i, j, typeCode, mbrNum;
|
|
||||||
char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe)
|
|
||||||
char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
|
|
||||||
|
|
||||||
cout << "\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n"
|
|
||||||
<< "to use one, just hit the Enter key at the below prompt and your MBR\n"
|
|
||||||
<< "partition table will be untouched.\n\n\a";
|
|
||||||
|
|
||||||
// Now get the numbers of up to three partitions to add to the
|
|
||||||
// hybrid MBR....
|
|
||||||
cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n"
|
|
||||||
<< "added to the hybrid MBR, in sequence: ";
|
|
||||||
junk = fgets(line, 255, stdin);
|
|
||||||
numParts = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]);
|
|
||||||
|
|
||||||
if (numParts > 0) {
|
|
||||||
// Blank out the protective MBR, but leave the boot loader code
|
|
||||||
// alone....
|
|
||||||
protectiveMBR.EmptyMBR(0);
|
|
||||||
protectiveMBR.SetDiskSize(diskSize);
|
|
||||||
cout << "Place EFI GPT (0xEE) partition first in MBR (good for GRUB)? ";
|
|
||||||
eeFirst = GetYN();
|
|
||||||
} // if
|
|
||||||
|
|
||||||
for (i = 0; i < numParts; i++) {
|
|
||||||
j = partNums[i] - 1;
|
|
||||||
cout << "\nCreating entry for partition #" << j + 1 << "\n";
|
|
||||||
if (eeFirst == 'Y')
|
|
||||||
mbrNum = i + 1;
|
|
||||||
else
|
|
||||||
mbrNum = i;
|
|
||||||
numConverted += OnePartToMBR(j, mbrNum);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
if ((numParts > 0) && (numConverted > 0)) { // User opted to create a hybrid MBR....
|
|
||||||
// Create EFI protective partition that covers the start of the disk.
|
|
||||||
// If this location (covering the main GPT data structures) is omitted,
|
|
||||||
// Linux won't find any partitions on the disk. Note that this is
|
|
||||||
// NUMBERED AFTER the hybrid partitions, contrary to what the
|
|
||||||
// gptsync utility does. This is because Windows seems to choke on
|
|
||||||
// disks with a 0xEE partition in the first slot and subsequent
|
|
||||||
// additional partitions, unless it boots from the disk.
|
|
||||||
if (eeFirst == 'Y')
|
|
||||||
mbrNum = 0;
|
|
||||||
else
|
|
||||||
mbrNum = numParts;
|
|
||||||
protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), 0xEE);
|
|
||||||
protectiveMBR.SetHybrid();
|
|
||||||
|
|
||||||
// ... and for good measure, if there are any partition spaces left,
|
|
||||||
// optionally create another protective EFI partition to cover as much
|
|
||||||
// space as possible....
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
if (protectiveMBR.GetType(i) == 0x00) { // unused entry....
|
if (gptParts[i] >= 0) {
|
||||||
if (fillItUp == 'M') {
|
numConverted += OnePartToMBR((uint32_t) gptParts[i], i);
|
||||||
cout << "\nUnused partition space(s) found. Use one to protect more partitions? ";
|
if (mbrTypes[i] != 0)
|
||||||
fillItUp = GetYN();
|
protectiveMBR.SetPartType(i, mbrTypes[i]);
|
||||||
typeCode = 0x00; // use this to flag a need to get type code
|
|
||||||
} // if
|
} // if
|
||||||
if (fillItUp == 'Y') {
|
} // for (regular partition pass)
|
||||||
while ((typeCode <= 0) || (typeCode > 255)) {
|
for (i = 0; i < 4; i++) {
|
||||||
cout << "Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): ";
|
if (gptParts[i] == MBR_EFI_GPT) {
|
||||||
// Comment on above: Mac OS treats disks with more than one
|
if (protectiveMBR.FindFirstAvailable() == UINT32_C(1)) {
|
||||||
// 0xEE MBR partition as MBR disks, not as GPT disks.
|
protectiveMBR.MakePart(i, 1, protectiveMBR.FindLastInFree(1), mbrTypes[i]);
|
||||||
junk = fgets(line, 255, stdin);
|
protectiveMBR.SetHybrid();
|
||||||
sscanf(line, "%x", &typeCode);
|
} else {
|
||||||
if (line[0] == '\n')
|
protectiveMBR.MakeBiggestPart(i, mbrTypes[i]);
|
||||||
typeCode = 0;
|
} // if/else
|
||||||
} // while
|
} // if EFI GPT partition specified
|
||||||
protectiveMBR.MakeBiggestPart(i, typeCode); // make a partition
|
} // for (0xEE pass)
|
||||||
} // if (fillItUp == 'Y')
|
} // if arrays were passed
|
||||||
} // if unused entry
|
return numConverted;
|
||||||
} // for (i = 0; i < 4; i++)
|
} // GPTData::PartsToMBR()
|
||||||
} // if (numParts > 0)
|
|
||||||
} // GPTData::MakeHybrid()
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* *
|
* *
|
||||||
@@ -1813,8 +1524,8 @@ void GPTData::MakeHybrid(void) {
|
|||||||
// necessary, copies data if it already exists. Returns 1 if all goes
|
// necessary, copies data if it already exists. Returns 1 if all goes
|
||||||
// well, 0 if an error is encountered.
|
// well, 0 if an error is encountered.
|
||||||
int GPTData::SetGPTSize(uint32_t numEntries) {
|
int GPTData::SetGPTSize(uint32_t numEntries) {
|
||||||
struct GPTPart* newParts;
|
GPTPart* newParts;
|
||||||
struct GPTPart* trash;
|
GPTPart* trash;
|
||||||
uint32_t i, high, copyNum;
|
uint32_t i, high, copyNum;
|
||||||
int allOK = 1;
|
int allOK = 1;
|
||||||
|
|
||||||
@@ -1907,10 +1618,8 @@ int GPTData::DeletePartition(uint32_t partNum) {
|
|||||||
return retval;
|
return retval;
|
||||||
} // GPTData::DeletePartition(uint32_t partNum)
|
} // GPTData::DeletePartition(uint32_t partNum)
|
||||||
|
|
||||||
// Non-interactively create a partition. Note that this function is overloaded
|
// Non-interactively create a partition.
|
||||||
// with another of the same name but different parameters; that one prompts
|
// Returns 1 if the operation was successful, 0 if a problem was discovered.
|
||||||
// the user for data. This one returns 1 if the operation was successful, 0
|
|
||||||
// if a problem was discovered.
|
|
||||||
uint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) {
|
uint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector) {
|
||||||
int retval = 1; // assume there'll be no problems
|
int retval = 1; // assume there'll be no problems
|
||||||
|
|
||||||
@@ -1931,7 +1640,6 @@ uint32_t GPTData::CreatePartition(uint32_t partNum, uint64_t startSector, uint64
|
|||||||
// Sort the GPT entries, eliminating gaps and making for a logical
|
// Sort the GPT entries, eliminating gaps and making for a logical
|
||||||
// ordering. Relies on QuickSortGPT() for the bulk of the work
|
// ordering. Relies on QuickSortGPT() for the bulk of the work
|
||||||
void GPTData::SortGPT(void) {
|
void GPTData::SortGPT(void) {
|
||||||
GPTPart temp;
|
|
||||||
uint32_t i, numFound, firstPart, lastPart;
|
uint32_t i, numFound, firstPart, lastPart;
|
||||||
|
|
||||||
// First, find the last partition with data, so as not to
|
// First, find the last partition with data, so as not to
|
||||||
@@ -1943,9 +1651,7 @@ void GPTData::SortGPT(void) {
|
|||||||
i = 0;
|
i = 0;
|
||||||
while (i < lastPart) {
|
while (i < lastPart) {
|
||||||
if (partitions[i].GetFirstLBA() == 0) {
|
if (partitions[i].GetFirstLBA() == 0) {
|
||||||
temp = partitions[i];
|
SwapPartitions(i, lastPart);
|
||||||
partitions[i] = partitions[lastPart];
|
|
||||||
partitions[lastPart] = temp;
|
|
||||||
do {
|
do {
|
||||||
lastPart--;
|
lastPart--;
|
||||||
} while ((lastPart > 0) && (partitions[lastPart].GetFirstLBA() == 0));
|
} while ((lastPart > 0) && (partitions[lastPart].GetFirstLBA() == 0));
|
||||||
@@ -1959,9 +1665,51 @@ void GPTData::SortGPT(void) {
|
|||||||
GetPartRange(&firstPart, &lastPart);
|
GetPartRange(&firstPart, &lastPart);
|
||||||
|
|
||||||
// Now call the recursive quick sort routine to do the real work....
|
// Now call the recursive quick sort routine to do the real work....
|
||||||
QuickSortGPT(partitions, 0, lastPart);
|
QuickSortGPT(0, lastPart);
|
||||||
} // GPTData::SortGPT()
|
} // GPTData::SortGPT()
|
||||||
|
|
||||||
|
// 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 GPTData::QuickSortGPT(int start, int finish) {
|
||||||
|
uint64_t starterValue; // starting location of median partition
|
||||||
|
int left, right;
|
||||||
|
|
||||||
|
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)
|
||||||
|
SwapPartitions(left++, right--);
|
||||||
|
} while (left <= right);
|
||||||
|
if (start < right) QuickSortGPT(start, right);
|
||||||
|
if (finish > left) QuickSortGPT(left, finish);
|
||||||
|
} // GPTData::QuickSortGPT()
|
||||||
|
|
||||||
|
// Swap the contents of two partitions.
|
||||||
|
// Returns 1 if successful, 0 if either partition is out of range
|
||||||
|
// (that is, not a legal number; either or both can be empty).
|
||||||
|
// Note that if partNum1 = partNum2 and this number is in range,
|
||||||
|
// it will be considered successful.
|
||||||
|
int GPTData::SwapPartitions(uint32_t partNum1, uint32_t partNum2) {
|
||||||
|
GPTPart temp;
|
||||||
|
int allOK = 1;
|
||||||
|
|
||||||
|
if ((partNum1 < mainHeader.numParts) && (partNum2 < mainHeader.numParts)) {
|
||||||
|
if (partNum1 != partNum2) {
|
||||||
|
temp = partitions[partNum1];
|
||||||
|
partitions[partNum1] = partitions[partNum2];
|
||||||
|
partitions[partNum2] = temp;
|
||||||
|
} // if
|
||||||
|
} else allOK = 0; // partition numbers are valid
|
||||||
|
return allOK;
|
||||||
|
} // GPTData::SwapPartitions()
|
||||||
|
|
||||||
// Set up data structures for entirely new set of partitions on the
|
// Set up data structures for entirely new set of partitions on the
|
||||||
// specified device. Returns 1 if OK, 0 if there were problems.
|
// specified device. Returns 1 if OK, 0 if there were problems.
|
||||||
// Note that this function does NOT clear the protectiveMBR data
|
// Note that this function does NOT clear the protectiveMBR data
|
||||||
@@ -2165,12 +1913,26 @@ int GPTData::GetPartRange(uint32_t *low, uint32_t *high) {
|
|||||||
return numFound;
|
return numFound;
|
||||||
} // GPTData::GetPartRange()
|
} // GPTData::GetPartRange()
|
||||||
|
|
||||||
|
// Returns the value of the first free partition, or -1 if none is
|
||||||
|
// unused.
|
||||||
|
int GPTData::FindFirstFreePart(void) {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (partitions != NULL) {
|
||||||
|
while ((partitions[i].IsUsed()) && (i < (int) mainHeader.numParts))
|
||||||
|
i++;
|
||||||
|
if (i >= (int) mainHeader.numParts)
|
||||||
|
i = -1;
|
||||||
|
} else i = -1;
|
||||||
|
return i;
|
||||||
|
} // GPTData::FindFirstFreePart()
|
||||||
|
|
||||||
// Returns the number of defined partitions.
|
// Returns the number of defined partitions.
|
||||||
uint32_t GPTData::CountParts(void) {
|
uint32_t GPTData::CountParts(void) {
|
||||||
uint32_t i, counted = 0;
|
uint32_t i, counted = 0;
|
||||||
|
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if (partitions[i].GetFirstLBA() > 0)
|
if (partitions[i].IsUsed())
|
||||||
counted++;
|
counted++;
|
||||||
} // for
|
} // for
|
||||||
return counted;
|
return counted;
|
||||||
@@ -2331,9 +2093,8 @@ int GPTData::IsFree(uint64_t sector) {
|
|||||||
int GPTData::IsFreePartNum(uint32_t partNum) {
|
int GPTData::IsFreePartNum(uint32_t partNum) {
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
|
|
||||||
if ((partNum >= 0) && (partNum < mainHeader.numParts)) {
|
if ((partNum < mainHeader.numParts) && (partitions != NULL)) {
|
||||||
if ((partitions[partNum].GetFirstLBA() != UINT64_C(0)) ||
|
if (partitions[partNum].IsUsed()) {
|
||||||
(partitions[partNum].GetLastLBA() != UINT64_C(0))) {
|
|
||||||
retval = 0;
|
retval = 0;
|
||||||
} // if partition is in use
|
} // if partition is in use
|
||||||
} else retval = 0;
|
} else retval = 0;
|
||||||
@@ -2361,8 +2122,7 @@ void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
|
|||||||
ReverseBytes(&header->numParts, 4);
|
ReverseBytes(&header->numParts, 4);
|
||||||
ReverseBytes(&header->sizeOfPartitionEntries, 4);
|
ReverseBytes(&header->sizeOfPartitionEntries, 4);
|
||||||
ReverseBytes(&header->partitionEntriesCRC, 4);
|
ReverseBytes(&header->partitionEntriesCRC, 4);
|
||||||
ReverseBytes(&header->reserved2, GPT_RESERVED);
|
ReverseBytes(header->reserved2, GPT_RESERVED);
|
||||||
// header->diskGUID.ReverseGUIDBytes();
|
|
||||||
} // GPTData::ReverseHeaderBytes()
|
} // GPTData::ReverseHeaderBytes()
|
||||||
|
|
||||||
// IMPORTANT NOTE: This function requires non-reversed mainHeader
|
// IMPORTANT NOTE: This function requires non-reversed mainHeader
|
||||||
|
|||||||
40
gpt.h
40
gpt.h
@@ -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;}
|
||||||
|
|||||||
39
gptpart.cc
39
gptpart.cc
@@ -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()
|
|
||||||
|
|||||||
@@ -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
58
mbr.cc
@@ -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
3
mbr.h
@@ -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);
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
76
sgdisk.8
76
sgdisk.8
@@ -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
|
||||||
|
|||||||
97
sgdisk.cc
97
sgdisk.cc
@@ -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()
|
||||||
|
|||||||
12
support.cc
12
support.cc
@@ -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
|
||||||
|
|||||||
@@ -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/
|
||||||
|
|||||||
Reference in New Issue
Block a user