summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsrs5694 <srs5694@users.sourceforge.net>2009-08-29 15:00:31 -0400
committersrs5694 <srs5694@users.sourceforge.net>2009-08-29 15:00:31 -0400
commit221e08768de7fe42ba533ca22baf671420569c07 (patch)
tree64f0b26992dc4f1100ab57f5bc32351272e3c9d2
parenta0eb11a64b4a5b78caff58f804a5fb78ddf3a5df (diff)
downloadsgdisk-221e08768de7fe42ba533ca22baf671420569c07.tar.gz
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.
-rw-r--r--CHANGELOG28
-rw-r--r--Makefile2
-rw-r--r--README14
-rw-r--r--attributes.cc3
-rw-r--r--attributes.h3
-rw-r--r--crc32.cc1
-rw-r--r--gdisk.847
-rw-r--r--gdisk.cc12
-rw-r--r--gpt.cc627
-rw-r--r--gpt.h49
-rw-r--r--mbr.cc171
-rw-r--r--mbr.h21
-rw-r--r--parttypes.cc3
-rw-r--r--parttypes.h3
-rw-r--r--support.cc22
-rw-r--r--support.h24
16 files changed, 616 insertions, 414 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 65229e7..420291b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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.
diff --git a/Makefile b/Makefile
index 2c55332..eb17c78 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/README b/README
index a212e8f..042418b 100644
--- a/README
+++ b/README
@@ -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
--------------
diff --git a/attributes.cc b/attributes.cc
index 1a299ea..73560d6 100644
--- a/attributes.cc
+++ b/attributes.cc
@@ -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
diff --git a/attributes.h b/attributes.h
index a7538a1..14329c6 100644
--- a/attributes.h
+++ b/attributes.h
@@ -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>
diff --git a/crc32.cc b/crc32.cc
index a446ffc..2b9ee9a 100644
--- a/crc32.cc
+++ b/crc32.cc
@@ -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
diff --git a/gdisk.8 b/gdisk.8
index 1207f87..714d300 100644
--- a/gdisk.8
+++ b/gdisk.8
@@ -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
@@ -258,12 +272,25 @@ 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.
diff --git a/gdisk.cc b/gdisk.cc
index 428111c..5baf9fe 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -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");
diff --git a/gpt.cc b/gpt.cc
index c06edfc..af3da2a 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -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("(Use the 's' item on the experts' menu.)\n");
- allOK = 0;
+ 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");
+ } 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("(Use the 's' item on the experts' menu.)\n");
- allOK = 0;
+ 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");
+ } // 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();
@@ -340,20 +424,30 @@ WhichToUse GPTData::UseWhichPartitions(void) {
if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) {
printf("\n\a***************************************************************\n"
- "Found invalid GPT and valid MBR; converting MBR to GPT format.\n"
+ "Found invalid GPT and valid MBR; converting MBR to GPT format.\n"
"THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n"
"you don't want to convert your MBR partitions to GPT format!\n"
"***************************************************************\n\n");
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,24 +1387,24 @@ 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,
- (uint32_t) length, typeCode, bootable);
+ 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",
j + 1);
@@ -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
@@ -1583,12 +1588,18 @@ int GPTData::SaveGPTData(void) {
* 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
if (allOK) { // writes completed OK
@@ -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,18 +1891,22 @@ 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
+// Determine endianness; set allOK = 0 if running on big-endian hardware
if (IsLittleEndian() == 0) {
fprintf(stderr, "\aRunning on big-endian hardware. Big-endian support is new and poorly"
" tested!\nBeware!\n");
diff --git a/gpt.h b/gpt.h
index d5057f6..2f405d5 100644
--- a/gpt.h
+++ b/gpt.h
@@ -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);
diff --git a/mbr.cc b/mbr.cc
index bf76d2c..b4bc6f4 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -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 ((blockSize = GetBlockSize(fd)) == -1) {
- blockSize = SECTOR_SIZE;
- printf("Unable to determine sector size; assuming %lu bytes!\n",
- (unsigned long) SECTOR_SIZE);
- } // if
+ 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()
diff --git a/mbr.h b/mbr.h
index 95ff4df..45159c1 100644
--- a/mbr.h
+++ b/mbr.h
@@ -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
diff --git a/parttypes.cc b/parttypes.cc
index cb61621..7e5a2a3 100644
--- a/parttypes.cc
+++ b/parttypes.cc
@@ -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
diff --git a/parttypes.h b/parttypes.h
index ad62027..7c336a4 100644
--- a/parttypes.h
+++ b/parttypes.h
@@ -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>
diff --git a/support.cc b/support.cc
index 1cef7d6..7ebec9a 100644
--- a/support.cc
+++ b/support.cc
@@ -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
@@ -177,8 +180,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) {
printf("\aWARNING! Sector size is not 512 bytes! This program is likely to ");
@@ -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 *
@@ -367,6 +377,11 @@ uint64_t disksize(int fd, int *err) {
#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) {
sz = 0;
@@ -379,5 +394,6 @@ uint64_t disksize(int fd, int *err) {
else
sectors = (b >> 9);
#endif
+#endif
return sectors;
}
diff --git a/support.h b/support.h
index d0b3e57..d812d3c 100644
--- a/support.h
+++ b/support.h
@@ -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);