New release: 0.4.0

This version adds support for FreeBSD and big-endian systems. It also
adds support for BSD disklabels and an assortment of other changes,
improvements, and bug fixes.
This commit is contained in:
srs5694
2009-08-29 15:00:31 -04:00
parent a0eb11a64b
commit 221e08768d
16 changed files with 616 additions and 414 deletions

View File

@@ -1,6 +1,34 @@
0.4.0:
------
- Added support for BSD disklabels. The program can now convert disks that
use "raw" disklabels, with the caveat that the first partition will
almost certainly need to be deleted because it'll overlap the main GPT
header; and convert disklabels contained within a GPT (or a former MBR,
converted to GPT) partition. In the latter case, the 'b' main menu option
is used.
- Added support for compiling on FreeBSD.
- Fixed bug that could cause crashes or incomplete sorts when sorting
the partition table.
- New partitions, including converted ones, now take on the name of the
partition type as a default name.
- Reorganized some code; created a separate C++ class for GPT partitions
(GPTPart), which replaced a struct and enabled moving code from the
bloated GPTData class into GPTPart.
- Fixed a bug that produced spurious warnings about unknown sector sizes
when loading a backup file.
0.3.5:
------
Note: This version was not officially publicly released; I wanted to test
the big-endian support while developing 0.4.0.
- Tweaked the disk type identification code to warn users to re-sync their
hybrid MBRs when one is detected.

View File

@@ -3,7 +3,7 @@ CXX=g++
#CFLAGS=-O2 -fpack-struct
CFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
LIB_NAMES=support crc32 mbr gpt parttypes attributes
LIB_NAMES=support crc32 gptpart mbr gpt bsd parttypes attributes
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)

14
README
View File

@@ -13,6 +13,9 @@ include:
* The ability to convert MBR-partitioned disks in-place to GPT format,
without losing data
* The ability to convert BSD disklabels in-place to create GPT
partitions, without losing data
* The ability to specify sector-exact partition sizes
* More flexible specification of filesystem type code GUIDs, which
@@ -27,6 +30,9 @@ include:
* The MBR boot loader code is left alone (GNU Parted tends to
wipe it out with every change)
* The ability to create a hybrid MBR, which permits GPT-unaware
OSes to access up to three GPT partitions on the disk
Of course, gdisk isn't without its limitations. Most notably, it lacks the
filesystem awareness and filesystem-related features of GNU Parted. You
can't resize a partition's filesystem or create a partition with a
@@ -60,10 +66,10 @@ with >2TiB drives, though.
My main development platform is a system running the 64-bit version of
Ubuntu 8.04. I've also tested on 64-bit OpenSuSE, 32-bit Fedora 10, 32-bit
Ubuntu 6.10, 64-bit Gentoo, 32-bit PowerPC Linux, and 32-bit Intel-based
Mac OS X. Problems relating to 64-bit integers on the 32-bit Linux have
been common during development and may crop up in the future. The Mac OS
X and big-endian (PowerPC) support is new.
Ubuntu 6.10, 64-bit Gentoo, 32-bit PowerPC Linux, 32-bit Intel-based Mac
OS X, and 64-bit Fedora 7.1. Problems relating to 64-bit integers on the
32-bit Linux have been common during development and may crop up in the
future. The Mac OS X, FreeBSD, and big-endian (PowerPC) support are new.
Redistribution
--------------

View File

@@ -2,6 +2,9 @@
// Class to manage partition attribute codes. These are binary bit fields,
// of which only three are currently (2/2009) documented on Wikipedia.
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS

View File

@@ -1,3 +1,6 @@
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>

View File

@@ -15,6 +15,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
* so make sure, you call it before using the other

47
gdisk.8
View File

@@ -1,13 +1,15 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH GDISK 8 "August 2009" "Linux 2.6" "GPT fdisk Manual"
.TH GDISK 8 "August 2009" "0.4.0" "GPT fdisk Manual"
.SH NAME
gdisk \- GPT partition table manipulator for Linux
gdisk \- GPT partition table manipulator for Linux and Unix
.SH SYNOPSIS
.BI "gdisk "
[ \-l ]
.I device
.SH DESCRIPTION
Hard disks can be divided into one or more segments, known as
.IR partitions .
This division is described in the
@@ -110,7 +112,7 @@ program employs a user interface similar to that of Linux's
but
.B "gdisk"
modifies GPT partitions. It also has the capability of transforming MBR
partitions into GPT partitions. Like the original
partitions or BSD disklabels into GPT partitions. Like the original
.B fdisk
program,
.B gdisk
@@ -120,8 +122,9 @@ save your partitions.
.B gdisk
is a text-mode menu-driven program for creation and manipulation of
partition tables. It will automatically convert an MBR partition table to
GPT format, or will load a GPT partition table. When used with the
partition tables. It will automatically convert an MBR partition table or
BSD disklabel stored without an MBR carrier partition to GPT format, or
will load a GPT partition table. When used with the
.IR "\-l"
command-line option, the program displays the current partition table and
then exits.
@@ -173,6 +176,13 @@ will note that
.B "gdisk"
lacks the options and limitations associated with CHS geometries.
For best results, you should always use an OS-specific partition table
program. For example, you should make Mac OS X partitions with the Mac OS
X Disk Utility
program and Linux partitions with the Linux
.B "gdisk"
or GNU Parted program.
Upon start,
.B gdisk
attempts to identify the partition type in use on the specified disk. If it
@@ -180,10 +190,14 @@ finds valid GPT data,
.B gdisk
will use it. If
.B gdisk
finds a valid MBR but no GPT data, it will attempt to convert the MBR into
GPT form. Upon exiting with the 'w' option,
finds a valid MBR or BSD disklabel but no GPT data, it will attempt to
convert the MBR or disklabel into GPT form. (BSD disklabels are likely to
have unusable first and/or final partitions because they overlap with the
GPT data structures, though.) GPT fdisk can identify, but not use data in,
Apple Partition Map (APM) disks, which are used on 680x0- and PowerPC-based
Macintoshes. Upon exiting with the 'w' option,
.B gdisk
will then replace the MBR with a GPT.
will then replace the MBR or disklabel with a GPT.
.IR "This action is potentially dangerous!"
Your system may become unbootable, and partition type codes may become
corrupted if the disk uses unrecognized type codes. Boot problems are
@@ -257,13 +271,26 @@ Most interactions with
occur with its interactive text-mode menus. The main menu provides the
following options:
.TP
.B b
Convert BSD partitions into GPT partitions. This option works on BSD
disklabels held within GPT (or converted MBR) partitions. Converted
partitions' type codes are likely to need manual adjustment.
.B gdisk
will attempt to convert BSD disklabels stored on the main disk when
launched, but this conversion is likely to produce first and/or last
partitions that are unusable. The many BSD variants means that the
probability of GPT fdisk being unable to convert a BSD disklabel are high
compared to the likelihood of problems with an MBR conversion.
.TP
.B c
Change the GPT name of a partition. This name is encoded as a UTF-16
string, but
.B gdisk
supports only ASCII characters as names. For the most part, Linux ignores
the partition name, but it may be important in some OSes.
the partition name, but it may be important in some OSes. GPT fdisk sets
a default name based on the partition type code.
.TP
.B d
@@ -342,7 +369,7 @@ Sort partition entries. GPT partition numbers need not match the order of
partitions on the disk. If you want them to match, you can use this option.
Note that some partitioning utilities, such as GNU Parted, will sort
partitions whenever they make changes. Such changes will be reflected in
your Linux device filenames, so you may need to edit
your device filenames, so you may need to edit
.IR "/etc/fstab"
if you use this option.

View File

@@ -4,6 +4,9 @@
//
// by Rod Smith, February 2009
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
//#include <iostream>
#include <stdio.h>
#include <string.h>
@@ -24,7 +27,7 @@ int main(int argc, char* argv[]) {
int doMore = 1;
char* device = NULL;
printf("GPT fdisk (gdisk) version 0.3.5\n\n");
printf("GPT fdisk (gdisk) version 0.4.0\n\n");
if (argc == 2) { // basic usage
if (SizesOK()) {
@@ -65,9 +68,9 @@ int DoCommand(char* filename, struct GPTData* theGPT) {
fgets(line, 255, stdin);
sscanf(line, "%c", &command);
switch (command) {
/* case 'b': case 'B':
GetGUID();
break; */
case 'b': case 'B':
theGPT->XFormDisklabel();
break;
case 'c': case 'C':
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
theGPT->SetName(theGPT->GetPartNum());
@@ -125,6 +128,7 @@ int DoCommand(char* filename, struct GPTData* theGPT) {
} // DoCommand()
void ShowCommands(void) {
printf("b\tconvert BSD disklabel partitions\n");
printf("c\tchange a partition's name\n");
printf("d\tdelete a partition\n");
printf("i\tshow detailed information on a partition\n");

617
gpt.cc
View File

@@ -3,6 +3,9 @@
/* By Rod Smith, January to February, 2009 */
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
@@ -17,6 +20,7 @@
#include <errno.h>
#include "crc32.h"
#include "gpt.h"
#include "bsd.h"
#include "support.h"
#include "parttypes.h"
#include "attributes.h"
@@ -39,6 +43,8 @@ GPTData::GPTData(void) {
secondCrcOk = 0;
mainPartsCrcOk = 0;
secondPartsCrcOk = 0;
apmFound = 0;
bsdFound = 0;
srand((unsigned int) time(NULL));
SetGPTSize(NUM_GPT_ENTRIES);
} // GPTData default constructor
@@ -54,6 +60,8 @@ GPTData::GPTData(char* filename) {
secondCrcOk = 0;
mainPartsCrcOk = 0;
secondPartsCrcOk = 0;
apmFound = 0;
bsdFound = 0;
srand((unsigned int) time(NULL));
LoadPartitions(filename);
} // GPTData(char* filename) constructor
@@ -65,8 +73,8 @@ GPTData::~GPTData(void) {
// Resizes GPT to specified number of entries. Creates a new table if
// necessary, copies data if it already exists.
int GPTData::SetGPTSize(uint32_t numEntries) {
struct GPTPartition* newParts;
struct GPTPartition* trash;
struct GPTPart* newParts;
struct GPTPart* trash;
uint32_t i, high, copyNum;
int allOK = 1;
@@ -79,7 +87,7 @@ int GPTData::SetGPTSize(uint32_t numEntries) {
printf("to %lu to fill the sector\n", (unsigned long) numEntries);
} // if
newParts = (struct GPTPartition*) calloc(numEntries, sizeof (struct GPTPartition));
newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart));
if (newParts != NULL) {
if (partitions != NULL) { // existing partitions; copy them over
GetPartRange(&i, &high);
@@ -120,22 +128,22 @@ int GPTData::SetGPTSize(uint32_t numEntries) {
} // GPTData::SetGPTSize()
// Checks to see if the GPT tables overrun existing partitions; if they
// do, issues a warning but takes no action. Returns 1 if all is OK, 0
// if problems were detected.
// do, issues a warning but takes no action. Returns number of problems
// detected (0 if OK, 1 to 2 if problems).
int GPTData::CheckGPTSize(void) {
uint64_t overlap, firstUsedBlock, lastUsedBlock;
uint32_t i;
int allOK = 1;
int numProbs = 0;
// first, locate the first & last used blocks
firstUsedBlock = UINT64_MAX;
lastUsedBlock = 0;
for (i = 0; i < mainHeader.numParts; i++) {
if ((partitions[i].firstLBA < firstUsedBlock) &&
(partitions[i].firstLBA != 0))
firstUsedBlock = partitions[i].firstLBA;
if (partitions[i].lastLBA > lastUsedBlock)
lastUsedBlock = partitions[i].lastLBA;
if ((partitions[i].GetFirstLBA() < firstUsedBlock) &&
(partitions[i].GetFirstLBA() != 0))
firstUsedBlock = partitions[i].GetFirstLBA();
if (partitions[i].GetLastLBA() > lastUsedBlock)
lastUsedBlock = partitions[i].GetLastLBA();
} // for
// If the disk size is 0 (the default), then it means that various
@@ -144,45 +152,121 @@ int GPTData::CheckGPTSize(void) {
if (diskSize != 0) {
if (mainHeader.firstUsableLBA > firstUsedBlock) {
overlap = mainHeader.firstUsableLBA - firstUsedBlock;
printf("Warning! Main partition table overlaps the first partition by %lu\n"
"blocks! Try reducing the partition table size by %lu entries.\n",
(unsigned long) overlap, (unsigned long) (overlap * 4));
printf("Warning! Main partition table overlaps the first partition by %lu blocks!\n",
(unsigned long) overlap);
if (firstUsedBlock > 2) {
printf("Try reducing the partition table size by %lu entries.\n",
(unsigned long) (overlap * 4));
printf("(Use the 's' item on the experts' menu.)\n");
allOK = 0;
} else {
printf("You will need to delete this partition or resize it in another utility.\n");
} // if/else
numProbs++;
} // Problem at start of disk
if (mainHeader.lastUsableLBA < lastUsedBlock) {
overlap = lastUsedBlock - mainHeader.lastUsableLBA;
printf("Warning! Secondary partition table overlaps the last partition by %lu\n"
"blocks! Try reducing the partition table size by %lu entries.\n",
(unsigned long) overlap, (unsigned long) (overlap * 4));
printf("Warning! Secondary partition table overlaps the last partition by %lu blocks\n",
(unsigned long) overlap);
if (lastUsedBlock > (diskSize - 2)) {
printf("You will need to delete this partition or resize it in another utility.\n");
} else {
printf("Try reducing the partition table size by %lu entries.\n",
(unsigned long) (overlap * 4));
printf("(Use the 's' item on the experts' menu.)\n");
allOK = 0;
} // if/else
numProbs++;
} // Problem at end of disk
} // if (diskSize != 0)
return allOK;
return numProbs;
} // GPTData::CheckGPTSize()
// Tell user whether Apple Partition Map (APM) was discovered....
void GPTData::ShowAPMState(void) {
if (apmFound)
printf(" APM: present\n");
else
printf(" APM: not present\n");
} // GPTData::ShowAPMState()
// Tell user about the state of the GPT data....
void GPTData::ShowGPTState(void) {
switch (state) {
case gpt_invalid:
printf(" GPT: not present\n");
break;
case gpt_valid:
printf(" GPT: present\n");
break;
case gpt_corrupt:
printf(" GPT: damaged\n");
break;
default:
printf("\a GPT: unknown -- bug!\n");
break;
} // switch
} // GPTData::ShowGPTState()
// Scan for partition data. This function loads the MBR data (regular MBR or
// protective MBR) and loads BSD disklabel data (which is probably invalid).
// It also looks for APM data, forces a load of GPT data, and summarizes
// the results.
void GPTData::PartitionScan(int fd) {
BSDData bsdDisklabel;
// int bsdFound;
printf("Partition table scan:\n");
// Read the MBR & check for BSD disklabel
protectiveMBR.ReadMBRData(fd);
protectiveMBR.ShowState();
bsdDisklabel.ReadBSDData(fd, 0, diskSize - 1);
bsdFound = bsdDisklabel.ShowState();
// bsdDisklabel.DisplayBSDData();
// Load the GPT data, whether or not it's valid
ForceLoadGPTData(fd);
ShowAPMState(); // Show whether there's an Apple Partition Map present
ShowGPTState(); // Show GPT status
printf("\n");
if (apmFound) {
printf("\n*******************************************************************\n");
printf("This disk appears to contain an Apple-format (APM) partition table!\n");
printf("It will be destroyed if you continue!\n");
printf("*******************************************************************\n\n\a");
} // if
/* if (bsdFound) {
printf("\n*************************************************************************\n");
printf("This disk appears to contain a BSD disklabel! It will be destroyed if you\n"
"continue!\n");
printf("*************************************************************************\n\n\a");
} // if */
} // GPTData::PartitionScan()
// Read GPT data from a disk.
int GPTData::LoadPartitions(char* deviceFilename) {
int fd, err;
int allOK = 1, i;
uint64_t firstBlock, lastBlock;
BSDData bsdDisklabel;
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
// store disk information....
diskSize = disksize(fd, &err);
blockSize = (uint32_t) GetBlockSize(fd);
strcpy(device, deviceFilename);
// Read the MBR
protectiveMBR.ReadMBRData(fd);
// Load the GPT data, whether or not it's valid
ForceLoadGPTData(fd);
PartitionScan(fd); // Check for partition types & print summary
switch (UseWhichPartitions()) {
case use_mbr:
XFormPartitions(&protectiveMBR);
XFormPartitions();
break;
case use_bsd:
bsdDisklabel.ReadBSDData(fd, 0, diskSize - 1);
// bsdDisklabel.DisplayBSDData();
ClearGPTData();
protectiveMBR.MakeProtectiveMBR(1); // clear boot area (option 1)
XFormDisklabel(&bsdDisklabel, 0);
break;
case use_gpt:
break;
@@ -197,11 +281,11 @@ int GPTData::LoadPartitions(char* deviceFilename) {
firstBlock = mainHeader.backupLBA; // start high
lastBlock = 0; // start low
for (i = 0; i < mainHeader.numParts; i++) {
if ((partitions[i].firstLBA < firstBlock) &&
(partitions[i].firstLBA > 0))
firstBlock = partitions[i].firstLBA;
if (partitions[i].lastLBA > lastBlock)
lastBlock = partitions[i].lastLBA;
if ((partitions[i].GetFirstLBA() < firstBlock) &&
(partitions[i].GetFirstLBA() > 0))
firstBlock = partitions[i].GetFirstLBA();
if (partitions[i].GetLastLBA() > lastBlock)
lastBlock = partitions[i].GetLastLBA();
} // for
} // if
CheckGPTSize();
@@ -347,13 +431,23 @@ WhichToUse GPTData::UseWhichPartitions(void) {
which = use_mbr;
} // if
if ((state == gpt_invalid) && bsdFound) {
printf("\n\a**********************************************************************\n"
"Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n"
"to GPT format. THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n"
"BSD partition will likely be unusable. Exit by typing 'q' if you don't\n"
"want to convert your BSD partitions to GPT format!\n"
"**********************************************************************\n\n");
which = use_bsd;
} // if
if ((state == gpt_valid) && (mbrState == gpt)) {
printf("Found valid GPT with protective MBR; using GPT.\n");
which = use_gpt;
} // if
if ((state == gpt_valid) && (mbrState == hybrid)) {
printf("Found valid GPT with hybrid MBR; using GPT.\n");
printf("\aIf you change GPT partitions' sizes, you may need to re-create the hybrid MBR!\n");
printf("\aIf you change GPT partitions, you may need to re-create the hybrid MBR!\n");
which = use_gpt;
} // if
if ((state == gpt_valid) && (mbrState == invalid)) {
@@ -445,7 +539,7 @@ int GPTData::GetPartRange(uint32_t *low, uint32_t *high) {
*high = 0;
if (mainHeader.numParts > 0) { // only try if partition table exists...
for (i = 0; i < mainHeader.numParts; i++) {
if (partitions[i].firstLBA != UINT64_C(0)) { // it exists
if (partitions[i].GetFirstLBA() != UINT64_C(0)) { // it exists
*high = i; // since we're counting up, set the high value
// Set the low value only if it's not yet found...
if (*low == (mainHeader.numParts + 1)) *low = i;
@@ -481,20 +575,7 @@ void GPTData::DisplayGPTData(void) {
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
for (i = 0; i < mainHeader.numParts; i++) {
if (partitions[i].firstLBA != 0) {
BytesToSI(blockSize * (partitions[i].lastLBA - partitions[i].firstLBA + 1),
sizeInSI);
printf("%4d %14lu %14lu", i + 1, (unsigned long) partitions[i].firstLBA,
(unsigned long) partitions[i].lastLBA);
printf(" %-10s %04X ", sizeInSI,
typeHelper.GUIDToID(partitions[i].partitionType));
j = 0;
while ((partitions[i].name[j] != '\0') && (j < 44)) {
printf("%c", partitions[i].name[j]);
j += 2;
} // while
printf("\n");
} // if
partitions[i].ShowSummary(i, blockSize, sizeInSI);
} // for
} // GPTData::DisplayGPTData()
@@ -514,33 +595,8 @@ void GPTData::ShowDetails(void) {
// Show detailed information on the specified partition
void GPTData::ShowPartDetails(uint32_t partNum) {
char temp[255];
int i;
uint64_t size;
if (partitions[partNum].firstLBA != 0) {
printf("Partition GUID code: %s ", GUIDToStr(partitions[partNum].partitionType, temp));
printf("(%s)\n", typeHelper.GUIDToName(partitions[partNum].partitionType, temp));
printf("Partition unique GUID: %s\n", GUIDToStr(partitions[partNum].uniqueGUID, temp));
printf("First sector: %llu (at %s)\n", (unsigned long long)
partitions[partNum].firstLBA,
BytesToSI(partitions[partNum].firstLBA * blockSize, temp));
printf("Last sector: %llu (at %s)\n", (unsigned long long)
partitions[partNum].lastLBA,
BytesToSI(partitions[partNum].lastLBA * blockSize, temp));
size = (partitions[partNum].lastLBA - partitions[partNum].firstLBA + 1);
printf("Partition size: %llu sectors (%s)\n", (unsigned long long)
size, BytesToSI(size * ((uint64_t) blockSize), temp));
printf("Attribute flags: %016llx\n", (unsigned long long)
partitions[partNum].attributes);
printf("Partition name: ");
i = 0;
while ((partitions[partNum].name[i] != '\0') && (i < NAME_SIZE)) {
printf("%c", partitions[partNum].name[i]);
i += 2;
} // while
printf("\n");
if (partitions[partNum].GetFirstLBA() != 0) {
partitions[partNum].ShowDetails(blockSize);
} else {
printf("Partition #%d does not exist.", (int) (partNum + 1));
} // if
@@ -553,7 +609,7 @@ void GPTData::CreatePartition(void) {
int partNum, firstFreePart = 0;
// Find first free partition...
while (partitions[firstFreePart].firstLBA != 0) {
while (partitions[firstFreePart].GetFirstLBA() != 0) {
firstFreePart++;
} // while
@@ -567,9 +623,9 @@ void GPTData::CreatePartition(void) {
mainHeader.numParts, firstFreePart + 1);
partNum = GetNumber(firstFreePart + 1, mainHeader.numParts,
firstFreePart + 1, prompt) - 1;
if (partitions[partNum].firstLBA != 0)
if (partitions[partNum].GetFirstLBA() != 0)
printf("partition %d is in use.\n", partNum + 1);
} while (partitions[partNum].firstLBA != 0);
} while (partitions[partNum].GetFirstLBA() != 0);
// Get first block for new partition...
sprintf(prompt, "First sector (%llu-%llu, default = %llu): ", firstBlock,
@@ -588,14 +644,12 @@ void GPTData::CreatePartition(void) {
} while (IsFree(sector) == 0);
lastBlock = sector;
partitions[partNum].firstLBA = firstBlock;
partitions[partNum].lastLBA = lastBlock;
partitions[partNum].SetFirstLBA(firstBlock);
partitions[partNum].SetLastLBA(lastBlock);
// rand() is only 32 bits on 32-bit systems, so multiply together to
// fill a 64-bit value.
partitions[partNum].uniqueGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
partitions[partNum].uniqueGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
ChangeGPTType(&partitions[partNum]);
partitions[partNum].SetUniqueGUID(1);
partitions[partNum].ChangeType();
partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType(prompt));
} else {
printf("No free sectors available\n");
} // if/else
@@ -610,11 +664,11 @@ void GPTData::DeletePartition(void) {
if (GetPartRange(&low, &high) > 0) {
sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
partNum = GetNumber(low + 1, high + 1, low, prompt);
BlankPartition(&partitions[partNum - 1]);
partitions[partNum - 1].BlankPartition();
} else {
printf("No partitions\n");
} // if/else
} // GPTData::DeletePartition
} // GPTData::DeletePartition()
// Find the first available block after the starting point; returns 0 if
// there are no available blocks left
@@ -638,9 +692,9 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) {
do {
firstMoved = 0;
for (i = 0; i < mainHeader.numParts; i++) {
if ((first >= partitions[i].firstLBA) &&
(first <= partitions[i].lastLBA)) { // in existing part.
first = partitions[i].lastLBA + 1;
if ((first >= partitions[i].GetFirstLBA()) &&
(first <= partitions[i].GetLastLBA())) { // in existing part.
first = partitions[i].GetLastLBA() + 1;
firstMoved = 1;
} // if
} // for
@@ -668,9 +722,9 @@ uint64_t GPTData::FindLastAvailable(uint64_t start) {
do {
lastMoved = 0;
for (i = 0; i < mainHeader.numParts; i++) {
if ((last >= partitions[i].firstLBA) &&
(last <= partitions[i].lastLBA)) { // in existing part.
last = partitions[i].firstLBA - 1;
if ((last >= partitions[i].GetFirstLBA()) &&
(last <= partitions[i].GetLastLBA())) { // in existing part.
last = partitions[i].GetFirstLBA() - 1;
lastMoved = 1;
} // if
} // for
@@ -687,9 +741,9 @@ uint64_t GPTData::FindLastInFree(uint64_t start) {
nearestStart = mainHeader.lastUsableLBA;
for (i = 0; i < mainHeader.numParts; i++) {
if ((nearestStart > partitions[i].firstLBA) &&
(partitions[i].firstLBA > start)) {
nearestStart = partitions[i].firstLBA - 1;
if ((nearestStart > partitions[i].GetFirstLBA()) &&
(partitions[i].GetFirstLBA() > start)) {
nearestStart = partitions[i].GetFirstLBA() - 1;
} // if
} // for
return (nearestStart);
@@ -701,8 +755,8 @@ int GPTData::IsFree(uint64_t sector) {
uint32_t i;
for (i = 0; i < mainHeader.numParts; i++) {
if ((sector >= partitions[i].firstLBA) &&
(sector <= partitions[i].lastLBA)) {
if ((sector >= partitions[i].GetFirstLBA()) &&
(sector <= partitions[i].GetLastLBA())) {
isFree = 0;
} // if
} // for
@@ -713,10 +767,11 @@ int GPTData::IsFree(uint64_t sector) {
return (isFree);
} // GPTData::IsFree()
int GPTData::XFormPartitions(MBRData* origParts) {
int i, j;
int numToConvert;
int GPTData::XFormPartitions(void) {
int i, numToConvert;
uint8_t origType;
struct newGUID;
char name[NAME_SIZE];
// Clear out old data & prepare basics....
ClearGPTData();
@@ -728,24 +783,12 @@ int GPTData::XFormPartitions(MBRData* origParts) {
numToConvert = mainHeader.numParts;
for (i = 0; i < numToConvert; i++) {
origType = origParts->GetType(i);
// don't convert extended, hybrid protective, or null (non-existent) partitions
origType = protectiveMBR.GetType(i);
// don't waste CPU time trying to convert extended, hybrid protective, or
// null (non-existent) partitions
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
(origType != 0x00) && (origType != 0xEE)) {
partitions[i].firstLBA = (uint64_t) origParts->GetFirstSector(i);
partitions[i].lastLBA = partitions[i].firstLBA + (uint64_t)
origParts->GetLength(i) - 1;
partitions[i].partitionType = typeHelper.IDToGUID(((uint16_t) origType) * 0x0100);
// Create random unique GUIDs for the partitions
// rand() is only 32 bits, so multiply together to fill a 64-bit value
partitions[i].uniqueGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
partitions[i].uniqueGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
partitions[i].attributes = 0;
for (j = 0; j < NAME_SIZE; j++)
partitions[i].name[j] = '\0';
} // if
(origType != 0x00) && (origType != 0xEE))
partitions[i] = protectiveMBR.AsGPT(i);
} // for
// Convert MBR into protective MBR
@@ -756,18 +799,87 @@ int GPTData::XFormPartitions(MBRData* origParts) {
mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1;
return (1);
} // XFormPartitions()
} // GPTData::XFormPartitions()
// Transforms BSD disklable on the specified partition (numbered from 0).
// If an invalid partition number is given, the program prompts for one.
// Returns the number of new partitions created.
int GPTData::XFormDisklabel(int i) {
uint32_t low, high, partNum, startPart;
uint16_t hexCode;
int goOn = 1, numDone = 0;
BSDData disklabel;
if (GetPartRange(&low, &high) != 0) {
if ((i < low) || (i > high))
partNum = GetPartNum();
else
partNum = (uint32_t) i;
// Find the partition after the last used one
startPart = high + 1;
// Now see if the specified partition has a BSD type code....
hexCode = partitions[partNum].GetHexType();
if ((hexCode != 0xa500) && (hexCode != 0xa900)) {
printf("Specified partition doesn't have a disklabel partition type "
"code.\nContinue anyway?");
goOn = (GetYN() == 'Y');
} // if
// If all is OK, read the disklabel and convert it.
if (goOn) {
goOn = disklabel.ReadBSDData(device, partitions[partNum].GetFirstLBA(),
partitions[partNum].GetLastLBA());
if ((goOn) && (disklabel.IsDisklabel())) {
numDone = XFormDisklabel(&disklabel, startPart);
if (numDone == 1)
printf("Converted %d BSD partition.\n", numDone);
else
printf("Converted %d BSD partitions.\n", numDone);
} else {
printf("Unable to convert partitions! Unrecognized BSD disklabel.\n");
} // if/else
} // if
if (numDone > 0) { // converted partitions; delete carrier
partitions[partNum].BlankPartition();
} // if
} else {
printf("No partitions\n");
} // if/else
return numDone;
} // GPTData::XFormDisklable(int i)
// Transform the partitions on an already-loaded BSD disklabel...
int GPTData::XFormDisklabel(BSDData* disklabel, int startPart) {
int i, numDone = 0;
if ((disklabel->IsDisklabel()) && (startPart >= 0) &&
(startPart < mainHeader.numParts)) {
for (i = 0; i < disklabel->GetNumParts(); i++) {
partitions[i + startPart] = disklabel->AsGPT(i);
if (partitions[i + startPart].GetFirstLBA() != UINT64_C(0))
numDone++;
} // for
} // if
// Record that all original CRCs were OK so as not to raise flags
// when doing a disk verification
mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1;
return numDone;
} // GPTData::XFormDisklabel(BSDData* disklabel)
// Sort the GPT entries, eliminating gaps and making for a logical
// ordering. Relies on QuickSortGPT() for the bulk of the work
void GPTData::SortGPT(void) {
int i, lastPart = 0;
struct GPTPartition temp;
GPTPart temp;
// First, find the last partition with data, so as not to
// spend needless time sorting empty entries....
for (i = 0; i < GPT_SIZE; i++) {
if (partitions[i].firstLBA > 0)
for (i = 0; i < mainHeader.numParts; i++) {
if (partitions[i].GetFirstLBA() > 0)
lastPart = i;
} // for
@@ -775,7 +887,7 @@ void GPTData::SortGPT(void) {
// in the Quicksort function....
i = 0;
while (i < lastPart) {
if (partitions[i].firstLBA == 0) {
if (partitions[i].GetFirstLBA() == 0) {
temp = partitions[i];
partitions[i] = partitions[lastPart];
partitions[lastPart] = temp;
@@ -788,56 +900,12 @@ void GPTData::SortGPT(void) {
QuickSortGPT(partitions, 0, lastPart);
} // 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 QuickSortGPT(struct GPTPartition* partitions, int start, int finish) {
uint64_t starterValue; // starting location of median partition
int left, right;
struct GPTPartition temp;
left = start;
right = finish;
starterValue = partitions[(start + finish) / 2].firstLBA;
do {
while (partitions[left].firstLBA < starterValue)
left++;
while (partitions[right].firstLBA > 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()
// Blank (delete) a single partition
void BlankPartition(struct GPTPartition* partition) {
int j;
partition->uniqueGUID.data1 = 0;
partition->uniqueGUID.data2 = 0;
partition->partitionType.data1 = 0;
partition->partitionType.data2 = 0;
partition->firstLBA = 0;
partition->lastLBA = 0;
partition->attributes = 0;
for (j = 0; j < NAME_SIZE; j++)
partition->name[j] = '\0';
} // BlankPartition
// Blank the partition array
void GPTData::BlankPartitions(void) {
uint32_t i;
for (i = 0; i < mainHeader.numParts; i++) {
BlankPartition(&partitions[i]);
partitions[i].BlankPartition();
} // for
} // GPTData::BlankPartitions()
@@ -877,49 +945,16 @@ int GPTData::ClearGPTData(void) {
// Blank out the partitions array....
BlankPartitions();
// Flag all CRCs as being OK....
mainCrcOk = 1;
secondCrcOk = 1;
mainPartsCrcOk = 1;
secondPartsCrcOk = 1;
return (goOn);
} // GPTData::ClearGPTData()
// Returns 1 if the two partitions overlap, 0 if they don't
int TheyOverlap(struct GPTPartition* first, struct GPTPartition* second) {
int theyDo = 0;
// Don't bother checking unless these are defined (both start and end points
// are 0 for undefined partitions, so just check the start points)
if ((first->firstLBA != 0) && (second->firstLBA != 0)) {
if ((first->firstLBA < second->lastLBA) && (first->lastLBA >= second->firstLBA))
theyDo = 1;
if ((second->firstLBA < first->lastLBA) && (second->lastLBA >= first->firstLBA))
theyDo = 1;
} // if
return (theyDo);
} // Overlap()
// Change the type code on the specified partition.
// Note: The GPT CRCs must be recomputed after calling this function!
void ChangeGPTType(struct GPTPartition* part) {
char typeName[255], line[255];
uint16_t typeNum = 0xFFFF;
PartTypes typeHelper;
GUIDData newType;
printf("Current type is '%s'\n", typeHelper.GUIDToName(part->partitionType, typeName));
while ((!typeHelper.Valid(typeNum)) && (typeNum != 0)) {
printf("Hex code (L to show codes, 0 to enter raw code): ");
fgets(line, 255, stdin);
sscanf(line, "%x", &typeNum);
if (line[0] == 'L')
typeHelper.ShowTypes();
} // while
if (typeNum != 0) // user entered a code, so convert it
newType = typeHelper.IDToGUID(typeNum);
else // user wants to enter the GUID directly, so do that
newType = GetGUID();
part->partitionType = newType;
printf("Changed system type of partition to '%s'\n",
typeHelper.GUIDToName(part->partitionType, typeName));
} // ChangeGPTType()
// Prompt user for a partition number, then change its type code
// using ChangeGPTType(struct GPTPartition*) function.
void GPTData::ChangePartType(void) {
@@ -928,7 +963,7 @@ void GPTData::ChangePartType(void) {
if (GetPartRange(&low, &high) > 0) {
partNum = GetPartNum();
ChangeGPTType(&partitions[partNum]);
partitions[partNum].ChangeType();
} else {
printf("No partitions\n");
} // if/else
@@ -947,51 +982,20 @@ uint32_t GPTData::GetPartNum(void) {
return (partNum - 1);
} // GPTData::GetPartNum()
// Prompt user for attributes to change on the specified partition
// and change them.
void GPTData::SetAttributes(uint32_t partNum) {
Attributes theAttr;
theAttr.SetAttributes(partitions[partNum].attributes);
theAttr.SetAttributes(partitions[partNum].GetAttributes());
theAttr.DisplayAttributes();
theAttr.ChangeAttributes();
partitions[partNum].attributes = theAttr.GetAttributes();
partitions[partNum].SetAttributes(theAttr.GetAttributes());
} // GPTData::SetAttributes()
// Set the name for a partition to theName, or prompt for a name if
// theName is a NULL pointer. Note that theName is a standard C-style
// string, although the GUID partition definition requires a UTF-16LE
// string. This function creates a simple-minded copy for this.
void GPTData::SetName(uint32_t partNum, char* theName) {
char newName[NAME_SIZE]; // New name
int i;
// Blank out new name string, just to be on the safe side....
for (i = 0; i < NAME_SIZE; i++)
newName[i] = '\0';
if (theName == NULL) { // No name specified, so get one from the user
printf("Enter name: ");
fgets(newName, NAME_SIZE / 2, stdin);
// Input is likely to include a newline, so remove it....
i = strlen(newName);
if (newName[i - 1] == '\n')
newName[i - 1] = '\0';
} else {
strcpy(newName, theName);
} // if
// Copy the C-style ASCII string from newName into a form that the GPT
// table will accept....
for (i = 0; i < NAME_SIZE; i++) {
if ((i % 2) == 0) {
partitions[partNum].name[i] = newName[(i / 2)];
} else {
partitions[partNum].name[i] = '\0';
} // if/else
} // for
} // GPTData::SetName()
if ((partNum >= 0) && (partNum < mainHeader.numParts))
if (partitions[partNum].GetFirstLBA() > 0)
partitions[partNum].SetName((unsigned char*) theName);
} // GPTData::SetName
// Set the disk GUID to the specified value. Note that the header CRCs must
// be recomputed after calling this function.
@@ -1007,8 +1011,8 @@ int GPTData::SetPartitionGUID(uint32_t pn, GUIDData theGUID) {
int retval = 0;
if (pn < mainHeader.numParts) {
if (partitions[pn].firstLBA != UINT64_C(0)) {
partitions[pn].uniqueGUID = theGUID;
if (partitions[pn].GetFirstLBA() != UINT64_C(0)) {
partitions[pn].SetUniqueGUID(theGUID);
retval = 1;
} // if
} // if
@@ -1024,8 +1028,8 @@ int GPTData::CheckHeaderValidity(void) {
if (mainHeader.signature != GPT_SIGNATURE) {
valid -= 1;
printf("Main GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
(unsigned long long) mainHeader.signature, (unsigned long long) GPT_SIGNATURE);
// printf("Main GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
// (unsigned long long) mainHeader.signature, (unsigned long long) GPT_SIGNATURE);
} else if ((mainHeader.revision != 0x00010000) && valid) {
valid -= 1;
printf("Unsupported GPT version in main header; read 0x%08lX, should be\n0x%08lX\n",
@@ -1034,8 +1038,8 @@ int GPTData::CheckHeaderValidity(void) {
if (secondHeader.signature != GPT_SIGNATURE) {
valid -= 2;
printf("Secondary GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
(unsigned long long) secondHeader.signature, (unsigned long long) GPT_SIGNATURE);
// printf("Secondary GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
// (unsigned long long) secondHeader.signature, (unsigned long long) GPT_SIGNATURE);
} else if ((secondHeader.revision != 0x00010000) && valid) {
valid -= 2;
printf("Unsupported GPT version in backup header; read 0x%08lX, should be\n0x%08lX\n",
@@ -1046,9 +1050,7 @@ int GPTData::CheckHeaderValidity(void) {
if ((protectiveMBR.GetValidity() == invalid) &&
(((mainHeader.signature << 32) == APM_SIGNATURE1) ||
(mainHeader.signature << 32) == APM_SIGNATURE2)) {
printf("\n*******************************************************************\n");
printf("This disk appears to contain an Apple-format (APM) partition table!\n");
printf("*******************************************************************\n\n\a");
apmFound = 1; // Will display warning message later
} // if
return valid;
@@ -1064,7 +1066,7 @@ int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
// computation to be valid
oldCRC = header->headerCRC;
if (IsLittleEndian() == 0)
ReverseBytes((char*) &oldCRC, 4);
ReverseBytes(&oldCRC, 4);
header->headerCRC = UINT32_C(0);
// Initialize CRC functions...
@@ -1091,13 +1093,13 @@ void GPTData::RecomputeCRCs(void) {
// Compute CRC of partition tables & store in main and secondary headers
trueNumParts = mainHeader.numParts;
if (littleEndian == 0)
ReverseBytes((char*) &trueNumParts, 4); // unreverse this key piece of data....
ReverseBytes(&trueNumParts, 4); // unreverse this key piece of data....
crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
mainHeader.partitionEntriesCRC = crc;
secondHeader.partitionEntriesCRC = crc;
if (littleEndian == 0) {
ReverseBytes((char*) &mainHeader.partitionEntriesCRC, 4);
ReverseBytes((char*) &secondHeader.partitionEntriesCRC, 4);
ReverseBytes(&mainHeader.partitionEntriesCRC, 4);
ReverseBytes(&secondHeader.partitionEntriesCRC, 4);
} // if
// Zero out GPT tables' own CRCs (required for correct computation)
@@ -1107,11 +1109,11 @@ void GPTData::RecomputeCRCs(void) {
// Compute & store CRCs of main & secondary headers...
crc = chksum_crc32((unsigned char*) &mainHeader, HEADER_SIZE);
if (littleEndian == 0)
ReverseBytes((char*) &crc, 4);
ReverseBytes(&crc, 4);
mainHeader.headerCRC = crc;
crc = chksum_crc32((unsigned char*) &secondHeader, HEADER_SIZE);
if (littleEndian == 0)
ReverseBytes((char*) &crc, 4);
ReverseBytes(&crc, 4);
secondHeader.headerCRC = crc;
} // GPTData::RecomputeCRCs()
@@ -1213,19 +1215,22 @@ int GPTData::Verify(void) {
// Check for overlapping partitions....
for (i = 1; i < mainHeader.numParts; i++) {
for (j = 0; j < i; j++) {
if (TheyOverlap(&partitions[i], &partitions[j])) {
if (partitions[i].DoTheyOverlap(&partitions[j])) {
problems++;
printf("\nProblem: partitions %d and %d overlap:\n", i + 1, j + 1);
printf(" Partition %d: %llu to %llu\n", i,
(unsigned long long) partitions[i].firstLBA,
(unsigned long long) partitions[i].lastLBA);
(unsigned long long) partitions[i].GetFirstLBA(),
(unsigned long long) partitions[i].GetLastLBA());
printf(" Partition %d: %llu to %llu\n", j,
(unsigned long long) partitions[j].firstLBA,
(unsigned long long) partitions[j].lastLBA);
(unsigned long long) partitions[j].GetFirstLBA(),
(unsigned long long) partitions[j].GetLastLBA());
} // if
} // for j...
} // for i...
// Verify that partitions don't run into GPT data areas....
problems += CheckGPTSize();
// Now compute available space, but only if no problems found, since
// problems could affect the results
if (problems == 0) {
@@ -1382,23 +1387,23 @@ void GPTData::MakeHybrid(void) {
j = partNums[i] - 1;
printf("\nCreating entry for partition #%d\n", j + 1);
if ((j >= 0) && (j < mainHeader.numParts)) {
if (partitions[j].lastLBA < UINT32_MAX) {
if (partitions[j].GetLastLBA() < UINT32_MAX) {
do {
printf("Enter an MBR hex code (default %02X): ",
typeHelper.GUIDToID(partitions[j].partitionType) / 256);
typeHelper.GUIDToID(partitions[j].GetType()) / 256);
fgets(line, 255, stdin);
sscanf(line, "%x", &typeCode);
if (line[0] == '\n')
typeCode = typeHelper.GUIDToID(partitions[j].partitionType) / 256;
typeCode = partitions[j].GetHexType() / 256;
} while ((typeCode <= 0) || (typeCode > 255));
printf("Set the bootable flag? ");
bootable = (GetYN() == 'Y');
length = partitions[j].lastLBA - partitions[j].firstLBA + UINT64_C(1);
length = partitions[j].GetLengthLBA();
if (eeFirst == 'Y')
mbrNum = i + 1;
else
mbrNum = i;
protectiveMBR.MakePart(mbrNum, (uint32_t) partitions[j].firstLBA,
protectiveMBR.MakePart(mbrNum, (uint32_t) partitions[j].GetFirstLBA(),
(uint32_t) length, typeCode, bootable);
} else { // partition out of range
printf("Partition %d ends beyond the 2TiB limit of MBR partitions; omitting it.\n",
@@ -1472,7 +1477,7 @@ int GPTData::SaveGPTData(void) {
// First do some final sanity checks....
// Is there enough space to hold the GPT headers and partition tables,
// given the partition sizes?
if (CheckGPTSize() == 0) {
if (CheckGPTSize() > 0) {
allOK = 0;
} // if
@@ -1488,14 +1493,14 @@ int GPTData::SaveGPTData(void) {
// Check for overlapping partitions....
for (i = 1; i < mainHeader.numParts; i++) {
for (j = 0; j < i; j++) {
if (TheyOverlap(&partitions[i], &partitions[j])) {
if (partitions[i].DoTheyOverlap(&partitions[j])) {
fprintf(stderr, "\Error: partitions %d and %d overlap:\n", i + 1, j + 1);
fprintf(stderr, " Partition %d: %llu to %llu\n", i,
(unsigned long long) partitions[i].firstLBA,
(unsigned long long) partitions[i].lastLBA);
(unsigned long long) partitions[i].GetFirstLBA(),
(unsigned long long) partitions[i].GetLastLBA());
fprintf(stderr, " Partition %d: %llu to %llu\n", j,
(unsigned long long) partitions[j].firstLBA,
(unsigned long long) partitions[j].lastLBA);
(unsigned long long) partitions[j].GetFirstLBA(),
(unsigned long long) partitions[j].GetLastLBA());
fprintf(stderr, "Aborting write operation!\n");
allOK = 0;
} // if
@@ -1582,12 +1587,18 @@ int GPTData::SaveGPTData(void) {
* it definitely will get things on disk though:
* http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
#else
#ifdef __FreeBSD__
sleep(2);
i = ioctl(fd, DIOCGFLUSH);
printf("Warning: The kernel is still using the old partition table.\n");
#else
sleep(2);
i = ioctl(fd, BLKRRPART);
if (i)
printf("Warning: The kernel is still using the old partition table.\n"
"The new table will be used at the next reboot.\n");
#endif
#endif
} // if
@@ -1691,7 +1702,7 @@ int GPTData::LoadGPTBackup(char* filename) {
littleEndian = 0;
// Let the MBRData class load the saved MBR...
protectiveMBR.ReadMBRData(fd);
protectiveMBR.ReadMBRData(fd, 0); // 0 = don't check block size
// Load the main GPT header, check its vaility, and set the GPT
// size based on the data
@@ -1815,22 +1826,22 @@ int GPTData::DestroyGPT(void) {
} // GPTData::DestroyGPT()
void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
ReverseBytes((char*) &header->signature, 8);
ReverseBytes((char*) &header->revision, 4);
ReverseBytes((char*) &header->headerSize, 4);
ReverseBytes((char*) &header->headerCRC, 4);
ReverseBytes((char*) &header->reserved, 4);
ReverseBytes((char*) &header->currentLBA, 8);
ReverseBytes((char*) &header->backupLBA, 8);
ReverseBytes((char*) &header->firstUsableLBA, 8);
ReverseBytes((char*) &header->lastUsableLBA, 8);
ReverseBytes((char*) &header->partitionEntriesLBA, 8);
ReverseBytes((char*) &header->numParts, 4);
ReverseBytes((char*) &header->sizeOfPartitionEntries, 4);
ReverseBytes((char*) &header->partitionEntriesCRC, 4);
ReverseBytes((char*) header->reserved2, GPT_RESERVED);
ReverseBytes((char*) &header->diskGUID.data1, 8);
ReverseBytes((char*) &header->diskGUID.data2, 8);
ReverseBytes(&header->signature, 8);
ReverseBytes(&header->revision, 4);
ReverseBytes(&header->headerSize, 4);
ReverseBytes(&header->headerCRC, 4);
ReverseBytes(&header->reserved, 4);
ReverseBytes(&header->currentLBA, 8);
ReverseBytes(&header->backupLBA, 8);
ReverseBytes(&header->firstUsableLBA, 8);
ReverseBytes(&header->lastUsableLBA, 8);
ReverseBytes(&header->partitionEntriesLBA, 8);
ReverseBytes(&header->numParts, 4);
ReverseBytes(&header->sizeOfPartitionEntries, 4);
ReverseBytes(&header->partitionEntriesCRC, 4);
ReverseBytes(&header->reserved2, GPT_RESERVED);
ReverseBytes(&header->diskGUID.data1, 8);
ReverseBytes(&header->diskGUID.data2, 8);
} // GPTData::ReverseHeaderBytes()
// IMPORTANT NOTE: This function requires non-reversed mainHeader
@@ -1846,13 +1857,7 @@ void GPTData::ReversePartitionBytes() {
"data corruption or a misplaced call to this function.\n");
} // if signature mismatch....
for (i = 0; i < mainHeader.numParts; i++) {
ReverseBytes((char*) &partitions[i].partitionType.data1, 8);
ReverseBytes((char*) &partitions[i].partitionType.data2, 8);
ReverseBytes((char*) &partitions[i].uniqueGUID.data1, 8);
ReverseBytes((char*) &partitions[i].uniqueGUID.data2, 8);
ReverseBytes((char*) &partitions[i].firstLBA, 8);
ReverseBytes((char*) &partitions[i].lastLBA, 8);
ReverseBytes((char*) &partitions[i].attributes, 8);
partitions[i].ReversePartBytes();
} // for
} // GPTData::ReversePartitionBytes()
@@ -1886,15 +1891,19 @@ int SizesOK(void) {
allOK = 0;
} // if
if (sizeof(struct MBRRecord) != 16) {
fprintf(stderr, "MBRRecord is %d bytes, should be 16 bytes; aborting!\n", sizeof(uint32_t));
fprintf(stderr, "MBRRecord is %d bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord));
allOK = 0;
} // if
if (sizeof(struct EBRRecord) != 512) {
fprintf(stderr, "EBRRecord is %d bytes, should be 512 bytes; aborting!\n", sizeof(uint32_t));
fprintf(stderr, "EBRRecord is %d bytes, should be 512 bytes; aborting!\n", sizeof(EBRRecord));
allOK = 0;
} // if
if (sizeof(struct GPTHeader) != 512) {
fprintf(stderr, "GPTHeader is %d bytes, should be 512 bytes; aborting!\n", sizeof(uint32_t));
fprintf(stderr, "GPTHeader is %d bytes, should be 512 bytes; aborting!\n", sizeof(GPTHeader));
allOK = 0;
} // if
if (sizeof(GPTPart) != 128) {
fprintf(stderr, "GPTPart is %d bytes, should be 128 bytes; aborting!\n", sizeof(GPTPart));
allOK = 0;
} // if
// Determine endianness; set allOK = 0 if running on big-endian hardware

49
gpt.h
View File

@@ -1,34 +1,21 @@
/* gpt.h -- GPT and data structure definitions, types, and
functions */
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "support.h"
#include "parttypes.h"
#include "mbr.h"
#include "bsd.h"
#include "gptpart.h"
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
#define GPT_SIGNATURE UINT64_C(0x5452415020494645)
// Signatures for Apple (APM) disks, multiplied by 0x100000000
#define APM_SIGNATURE1 UINT64_C(0x00004D5000000000)
#define APM_SIGNATURE2 UINT64_C(0x0000535400000000)
/* Number and size of GPT entries... */
#define NUM_GPT_ENTRIES 128
#define GPT_SIZE 128
/* Offset, in 512-byte sectors, for GPT table and partition data.
Note this is above two multiplied together, divided by 512, with 2
added
#define GPT_OFFSET (((NUM_GPT_ENTRIES * GPT_SIZE) / SECTOR_SIZE) + 2)
*/
#define HEADER_SIZE 92
#define GPT_RESERVED 420
#define NAME_SIZE 72
using namespace std;
@@ -42,7 +29,7 @@ using namespace std;
enum GPTValidity {gpt_valid, gpt_corrupt, gpt_invalid};
// Which set of partition data to use
enum WhichToUse {use_gpt, use_mbr, use_new};
enum WhichToUse {use_gpt, use_mbr, use_bsd, use_new};
// Header (first 512 bytes) of GPT table
struct GPTHeader {
@@ -63,20 +50,11 @@ struct GPTHeader {
unsigned char reserved2[GPT_RESERVED];
}; // struct GPTHeader
struct GPTPartition {
struct GUIDData partitionType;
struct GUIDData uniqueGUID;
uint64_t firstLBA;
uint64_t lastLBA;
uint64_t attributes;
unsigned char name[NAME_SIZE];
}; // struct GPTPartition
// Data in GPT format
class GPTData {
protected:
struct GPTHeader mainHeader;
struct GPTPartition *partitions;
struct GPTPart *partitions;
struct GPTHeader secondHeader;
MBRData protectiveMBR;
char device[256]; // device filename
@@ -87,6 +65,8 @@ protected:
int secondCrcOk;
int mainPartsCrcOk;
int secondPartsCrcOk;
int apmFound; // set to 1 if APM detected
int bsdFound; // set to 1 if BSD disklabel detected in MBR
// uint32_t units; // display units, in multiples of sectors
PartTypes typeHelper;
public:
@@ -95,6 +75,9 @@ public:
~GPTData(void);
int SetGPTSize(uint32_t numEntries);
int CheckGPTSize(void);
void ShowAPMState(void);
void ShowGPTState(void);
void PartitionScan(int fd);
int LoadPartitions(char* deviceFilename);
int ForceLoadGPTData(int fd);
int LoadMainTable(void);
@@ -112,7 +95,9 @@ public:
uint64_t FindLastAvailable(uint64_t start);
uint64_t FindLastInFree(uint64_t start);
int IsFree(uint64_t sector);
int XFormPartitions(MBRData* origParts);
int XFormPartitions(void);
int XFormDisklabel(int OnGptPart = -1);
int XFormDisklabel(BSDData* disklabel, int startPart);
void SortGPT(void);
int ClearGPTData(void);
void ChangePartType(void);
@@ -135,6 +120,8 @@ public:
int SaveGPTBackup(char* filename);
int LoadGPTBackup(char* filename);
int DestroyGPT(void); // Returns 1 if user proceeds
// Endianness functions
void ReverseHeaderBytes(struct GPTHeader* header); // for endianness
void ReversePartitionBytes(); // for endianness
@@ -150,8 +137,6 @@ public:
// Function prototypes....
void BlankPartition(struct GPTPartition* partition);
//int XFormType(uint8_t oldType, struct GUIDData* newType, int partNum);
void QuickSortGPT(struct GPTPartition* partitions, int start, int finish);
int TheyOverlap(struct GPTPartition* first, struct GPTPartition* second);
void ChangeGPTType(struct GPTPartition* part);
int SizesOK(void);

161
mbr.cc
View File

@@ -3,6 +3,9 @@
/* By Rod Smith, January to February, 2009 */
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
@@ -118,9 +121,10 @@ int MBRData::ReadMBRData(char* deviceFilename) {
} // MBRData::ReadMBRData(char* deviceFilename)
// Read data from MBR.
void MBRData::ReadMBRData(int fd) {
int allOK = 1, i, maxLogicals = 0;
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
int allOK = 1, i, j, maxLogicals = 0;
int err;
TempMBR tempMBR;
// Clear logical partition array
for (i = 0; i < NUM_LOGICALS; i++) {
@@ -136,39 +140,51 @@ void MBRData::ReadMBRData(int fd) {
logicals[i].lengthLBA = UINT32_C(0);
} // for
read(fd, code, 440);
read(fd, &diskSignature, 4);
read(fd, &nulls, 2);
read(fd, partitions, 64);
read(fd, &MBRSignature, 2);
err = lseek64(fd, 0, SEEK_SET);
err = read(fd, &tempMBR, 512);
for (i = 0; i < 440; i++)
code[i] = tempMBR.code[i];
diskSignature = tempMBR.diskSignature;
nulls = tempMBR.nulls;
for (i = 0; i < 4; i++) {
partitions[i].status = tempMBR.partitions[i].status;
partitions[i].partitionType = tempMBR.partitions[i].partitionType;
partitions[i].firstLBA = tempMBR.partitions[i].firstLBA;
partitions[i].lengthLBA = tempMBR.partitions[i].lengthLBA;
for (j = 0; j < 3; j++) {
partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
} // for j...
} // for i...
MBRSignature = tempMBR.MBRSignature;
// Reverse the byte order, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes((char*) &diskSignature, 4);
ReverseBytes((char*) &nulls, 2);
ReverseBytes((char*) &MBRSignature, 2);
ReverseBytes(&diskSignature, 4);
ReverseBytes(&nulls, 2);
ReverseBytes(&MBRSignature, 2);
for (i = 0; i < 4; i++) {
ReverseBytes((char*) &partitions[i].firstLBA, 4);
ReverseBytes((char*) &partitions[i].lengthLBA, 4);
ReverseBytes(&partitions[i].firstLBA, 4);
ReverseBytes(&partitions[i].lengthLBA, 4);
} // for
} // if
if (MBRSignature != MBR_SIGNATURE) {
allOK = 0;
state = invalid;
fprintf(stderr, "MBR signature invalid; read 0x%04X, but should be 0x%04X\n",
(unsigned int) MBRSignature, (unsigned int) MBR_SIGNATURE);
} /* if */
} // if
// Find disk size
diskSize = disksize(fd, &err);
// Find block size
if (checkBlockSize) {
if ((blockSize = GetBlockSize(fd)) == -1) {
blockSize = SECTOR_SIZE;
printf("Unable to determine sector size; assuming %lu bytes!\n",
(unsigned long) SECTOR_SIZE);
} // if
} // if (checkBlockSize)
// Load logical partition data, if any is found....
if (allOK) {
@@ -242,33 +258,55 @@ int MBRData::WriteMBRData(void) {
// Save the MBR data to a file. Note that this function writes ONLY the
// MBR data, not the logical partitions (if any are defined).
void MBRData::WriteMBRData(int fd) {
int i;
int i, j;
TempMBR tempMBR;
// Reverse the byte order, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes((char*) &diskSignature, 4);
ReverseBytes((char*) &nulls, 2);
ReverseBytes((char*) &MBRSignature, 2);
ReverseBytes(&diskSignature, 4);
ReverseBytes(&nulls, 2);
ReverseBytes(&MBRSignature, 2);
for (i = 0; i < 4; i++) {
ReverseBytes((char*) &partitions[i].firstLBA, 4);
ReverseBytes((char*) &partitions[i].lengthLBA, 4);
ReverseBytes(&partitions[i].firstLBA, 4);
ReverseBytes(&partitions[i].lengthLBA, 4);
} // for
} // if
write(fd, code, 440);
// Copy MBR data to a 512-byte data structure for writing, to
// work around a FreeBSD limitation....
for (i = 0; i < 440; i++)
tempMBR.code[i] = code[i];
tempMBR.diskSignature = diskSignature;
tempMBR.nulls = nulls;
tempMBR.MBRSignature = MBRSignature;
for (i = 0; i < 4; i++) {
tempMBR.partitions[i].status = partitions[i].status;
tempMBR.partitions[i].partitionType = partitions[i].partitionType;
tempMBR.partitions[i].firstLBA = partitions[i].firstLBA;
tempMBR.partitions[i].lengthLBA = partitions[i].lengthLBA;
for (j = 0; j < 3; j++) {
tempMBR.partitions[i].firstSector[j] = partitions[i].firstSector[j];
tempMBR.partitions[i].lastSector[j] = partitions[i].lastSector[j];
} // for j...
} // for i...
// Now write that data structure...
write(fd, &tempMBR, 512);
/* write(fd, code, 440);
write(fd, &diskSignature, 4);
write(fd, &nulls, 2);
write(fd, partitions, 64);
write(fd, &MBRSignature, 2);
write(fd, &MBRSignature, 2); */
// Reverse the byte order, if necessary
// Reverse the byte order back, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes((char*) &diskSignature, 4);
ReverseBytes((char*) &nulls, 2);
ReverseBytes((char*) &MBRSignature, 2);
ReverseBytes(&diskSignature, 4);
ReverseBytes(&nulls, 2);
ReverseBytes(&MBRSignature, 2);
for (i = 0; i < 4; i++) {
ReverseBytes((char*) &partitions[i].firstLBA, 4);
ReverseBytes((char*) &partitions[i].lengthLBA, 4);
ReverseBytes(&partitions[i].firstLBA, 4);
ReverseBytes(&partitions[i].lengthLBA, 4);
} // for
}// if
} // MBRData::WriteMBRData(int fd)
@@ -293,11 +331,11 @@ int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
(unsigned long) offset);
partNum = -1;
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
ReverseBytes((char*) &ebr.MBRSignature, 2);
ReverseBytes((char*) &ebr.partitions[0].firstLBA, 4);
ReverseBytes((char*) &ebr.partitions[0].lengthLBA, 4);
ReverseBytes((char*) &ebr.partitions[1].firstLBA, 4);
ReverseBytes((char*) &ebr.partitions[1].lengthLBA, 4);
ReverseBytes(&ebr.MBRSignature, 2);
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
} // if/else/if
if (ebr.MBRSignature != MBR_SIGNATURE) {
@@ -356,14 +394,19 @@ void MBRData::DisplayMBRData(void) {
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
} // MBRData::DisplayMBRData()
// Create a protective MBR
void MBRData::MakeProtectiveMBR(void) {
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
void MBRData::MakeProtectiveMBR(int clearBoot) {
int i;
// Initialize variables
nulls = 0;
MBRSignature = MBR_SIGNATURE;
if (clearBoot > 0) {
for (i = 0; i < 440; i++)
code[i] = (uint8_t) 0;
} // if
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
// Write CHS data. This maxes out the use of the disk, as much as
@@ -467,23 +510,24 @@ struct MBRRecord* MBRData::GetPartition(int i) {
return thePart;
} // GetPartition()
// Displays the state, as a word, on stdout. Used for debugging
// Displays the state, as a word, on stdout. Used for debugging & to
// tell the user about the MBR state when the program launches....
void MBRData::ShowState(void) {
switch (state) {
case invalid:
printf("invalid");
printf(" MBR: not present\n");
break;
case gpt:
printf("gpt");
printf(" MBR: protective\n");
break;
case hybrid:
printf("hybrid");
printf(" MBR: hybrid\n");
break;
case mbr:
printf("mbr");
printf(" MBR: MBR only\n");
break;
default:
printf("unknown -- bug!");
printf("\a MBR: unknown -- bug!\n");
break;
} // switch
} // MBRData::ShowState()
@@ -602,3 +646,36 @@ uint32_t MBRData::GetLength(int i) {
retval = UINT32_C(0);
return retval;
} // MBRData::GetLength()
// Return the MBR data as a GPT partition....
GPTPart MBRData::AsGPT(int i) {
MBRRecord* origPart;
GPTPart newPart;
uint8_t origType;
uint64_t firstSector, lastSector;
char tempStr[NAME_SIZE];
newPart.BlankPartition();
origPart = GetPartition(i);
if (origPart != NULL) {
origType = origPart->partitionType;
// don't convert extended, hybrid protective, or null (non-existent)
// partitions (Note similar protection is in GPTData::XFormPartitions(),
// but I want it here too in case I call this function in another
// context in the future....)
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
(origType != 0x00) && (origType != 0xEE)) {
firstSector = (uint64_t) origPart->firstLBA;
newPart.SetFirstLBA(firstSector);
lastSector = firstSector + (uint64_t) origPart->lengthLBA;
if (lastSector > 0) lastSector--;
newPart.SetLastLBA(lastSector);
newPart.SetType(((uint16_t) origType) * 0x0100);
newPart.SetUniqueGUID(1);
newPart.SetAttributes(0);
newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
} // if
} // if
return newPart;
} // MBRData::AsGPT()

21
mbr.h
View File

@@ -1,8 +1,12 @@
/* mbr.h -- MBR data structure definitions, types, and functions */
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "gptpart.h"
#ifndef __MBRSTRUCTS
#define __MBRSTRUCTS
@@ -32,6 +36,17 @@ struct MBRRecord {
uint32_t lengthLBA;
}; // struct MBRRecord
// Create a 512-byte data structure into which the MBR can be loaded in one
// go, for the benefit of FreeBSD which seems to flake out when loading
// from block devices in multiples other than the block size....
struct TempMBR {
uint8_t code[440];
uint32_t diskSignature;
uint16_t nulls;
struct MBRRecord partitions[4];
uint16_t MBRSignature;
}; // struct TempMBR
// Extended Boot Record (EBR) data, used to hold one logical partition's
// data within an extended partition. Includes pointer to next record for
// in-memory linked-list access. This is similar to MBRData, but with a
@@ -75,7 +90,7 @@ public:
void EmptyMBR(int clearBootloader = 1);
void SetDiskSize(uint64_t ds) {diskSize = ds;}
int ReadMBRData(char* deviceFilename);
void ReadMBRData(int fd);
void ReadMBRData(int fd, int checkBlockSize = 1);
int WriteMBRData(void);
void WriteMBRData(int fd);
// ReadLogicalPart() returns last partition # read to logicals[] array,
@@ -83,8 +98,9 @@ public:
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
int partNum);
void DisplayMBRData(void);
void MakeProtectiveMBR(void);
void MakeProtectiveMBR(int clearBoot = 0);
MBRValidity GetValidity(void) {return state;}
void ShowValidity(void);
void ShowState(void);
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
int bootable = 0);
@@ -99,6 +115,7 @@ public:
uint8_t GetType(int i);
uint32_t GetFirstSector(int i);
uint32_t GetLength(int i);
GPTPart AsGPT(int i);
}; // struct MBRData
#endif

View File

@@ -2,6 +2,9 @@
// Class to manage partition type codes -- a slight variant on MBR type
// codes, GUID type codes, and associated names.
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS

View File

@@ -1,3 +1,6 @@
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>

View File

@@ -3,6 +3,9 @@
// Primarily by Rod Smith, February 2009, but with a few functions
// copied from other sources (see attributions below).
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS
#define __STDC_CONSTANT_MACROS
@@ -176,8 +179,12 @@ int GetBlockSize(int fd) {
#ifdef __APPLE__
err = ioctl(fd, DKIOCGETBLOCKSIZE, &result);
#else
#ifdef __FreeBSD__
err = ioctl(fd, DIOCGSECTORSIZE, &result);
#else
err = ioctl(fd, BLKSSZGET, &result);
#endif
#endif
if (result != 512) {
@@ -319,15 +326,17 @@ int IsLittleEndian(void) {
} // IsLittleEndian()
// Reverse the byte order of theValue; numBytes is number of bytes
void ReverseBytes(char* theValue, int numBytes) {
void ReverseBytes(void* theValue, int numBytes) {
char* origValue;
char* tempValue;
int i;
origValue = (char*) theValue;
tempValue = (char*) malloc(numBytes);
for (i = 0; i < numBytes; i++)
tempValue[i] = theValue[i];
tempValue[i] = origValue[i];
for (i = 0; i < numBytes; i++)
theValue[i] = tempValue[numBytes - i - 1];
origValue[i] = tempValue[numBytes - i - 1];
free(tempValue);
} // ReverseBytes()
@@ -345,6 +354,7 @@ uint64_t PowerOf2(int value) {
return retval;
} // PowerOf2()
/**************************************************************************************
* *
* Below functions are lifted from various sources, as documented in comments before *
@@ -366,6 +376,11 @@ uint64_t disksize(int fd, int *err) {
// 32/64-bit issues on MacOS....
#ifdef __APPLE__
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, &sectors);
#else
#ifdef __FreeBSD__
*err = ioctl(fd, DIOCGMEDIASIZE, &sz);
b = GetBlockSize(fd);
sectors = sz / b;
#else
*err = ioctl(fd, BLKGETSIZE, &sz);
if (*err) {
@@ -378,6 +393,7 @@ uint64_t disksize(int fd, int *err) {
sectors = sz;
else
sectors = (b >> 9);
#endif
#endif
return sectors;
}

View File

@@ -1,8 +1,11 @@
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#ifdef __APPLE__
#if defined (__FreeBSD__) || defined (__APPLE__)
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
// This used to use __DARWIN_UNIX03 rather than __APPLE__, but __APPLE__
// is more general. If the code fails to work on older versions of OS X/
@@ -23,6 +26,23 @@
// Set this as a default
#define SECTOR_SIZE UINT32_C(512)
// Signatures for Apple (APM) disks, multiplied by 0x100000000
#define APM_SIGNATURE1 UINT64_C(0x00004D5000000000)
#define APM_SIGNATURE2 UINT64_C(0x0000535400000000)
/**************************
* Some GPT constants.... *
**************************/
#define GPT_SIGNATURE UINT64_C(0x5452415020494645)
// Number and size of GPT entries...
#define NUM_GPT_ENTRIES 128
#define GPT_SIZE 128
#define HEADER_SIZE 92
#define GPT_RESERVED 420
#define NAME_SIZE 72
using namespace std;
// a GUID
@@ -39,7 +59,7 @@ int GetBlockSize(int fd);
char* GUIDToStr(struct GUIDData theGUID, char* theString);
GUIDData GetGUID(void);
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
void ReverseBytes(char* theValue, int numBytes); // Reverses byte-order of theValue
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
uint64_t PowerOf2(int value);
uint64_t disksize(int fd, int* err);