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:
28
CHANGELOG
28
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:
|
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
|
- Tweaked the disk type identification code to warn users to re-sync their
|
||||||
hybrid MBRs when one is detected.
|
hybrid MBRs when one is detected.
|
||||||
|
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -3,7 +3,7 @@ CXX=g++
|
|||||||
#CFLAGS=-O2 -fpack-struct
|
#CFLAGS=-O2 -fpack-struct
|
||||||
CFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
|
CFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
|
||||||
CXXFLAGS=-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_SRCS=$(NAMES:=.cc)
|
||||||
LIB_OBJS=$(LIB_NAMES:=.o)
|
LIB_OBJS=$(LIB_NAMES:=.o)
|
||||||
LIB_HEADERS=$(LIB_NAMES:=.h)
|
LIB_HEADERS=$(LIB_NAMES:=.h)
|
||||||
|
|||||||
14
README
14
README
@@ -13,6 +13,9 @@ include:
|
|||||||
* The ability to convert MBR-partitioned disks in-place to GPT format,
|
* The ability to convert MBR-partitioned disks in-place to GPT format,
|
||||||
without losing data
|
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
|
* The ability to specify sector-exact partition sizes
|
||||||
|
|
||||||
* More flexible specification of filesystem type code GUIDs, which
|
* 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
|
* The MBR boot loader code is left alone (GNU Parted tends to
|
||||||
wipe it out with every change)
|
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
|
Of course, gdisk isn't without its limitations. Most notably, it lacks the
|
||||||
filesystem awareness and filesystem-related features of GNU Parted. You
|
filesystem awareness and filesystem-related features of GNU Parted. You
|
||||||
can't resize a partition's filesystem or create a partition with a
|
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
|
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 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
|
Ubuntu 6.10, 64-bit Gentoo, 32-bit PowerPC Linux, 32-bit Intel-based Mac
|
||||||
Mac OS X. Problems relating to 64-bit integers on the 32-bit Linux have
|
OS X, and 64-bit Fedora 7.1. Problems relating to 64-bit integers on the
|
||||||
been common during development and may crop up in the future. The Mac OS
|
32-bit Linux have been common during development and may crop up in the
|
||||||
X and big-endian (PowerPC) support is new.
|
future. The Mac OS X, FreeBSD, and big-endian (PowerPC) support are new.
|
||||||
|
|
||||||
Redistribution
|
Redistribution
|
||||||
--------------
|
--------------
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
// Class to manage partition attribute codes. These are binary bit fields,
|
// Class to manage partition attribute codes. These are binary bit fields,
|
||||||
// of which only three are currently (2/2009) documented on Wikipedia.
|
// 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_LIMIT_MACROS
|
||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
|
|||||||
@@ -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 <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
1
crc32.cc
1
crc32.cc
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
|
/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
|
||||||
* so make sure, you call it before using the other
|
* so make sure, you call it before using the other
|
||||||
|
|||||||
47
gdisk.8
47
gdisk.8
@@ -1,13 +1,15 @@
|
|||||||
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
|
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||||
.\" May be distributed under the GNU General Public License
|
.\" May be distributed under the GNU General Public License
|
||||||
.TH GDISK 8 "August 2009" "Linux 2.6" "GPT fdisk Manual"
|
.TH GDISK 8 "August 2009" "0.4.0" "GPT fdisk Manual"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
gdisk \- GPT partition table manipulator for Linux
|
gdisk \- GPT partition table manipulator for Linux and Unix
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.BI "gdisk "
|
.BI "gdisk "
|
||||||
[ \-l ]
|
[ \-l ]
|
||||||
.I device
|
.I device
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
|
|
||||||
Hard disks can be divided into one or more segments, known as
|
Hard disks can be divided into one or more segments, known as
|
||||||
.IR partitions .
|
.IR partitions .
|
||||||
This division is described in the
|
This division is described in the
|
||||||
@@ -110,7 +112,7 @@ program employs a user interface similar to that of Linux's
|
|||||||
but
|
but
|
||||||
.B "gdisk"
|
.B "gdisk"
|
||||||
modifies GPT partitions. It also has the capability of transforming MBR
|
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
|
.B fdisk
|
||||||
program,
|
program,
|
||||||
.B gdisk
|
.B gdisk
|
||||||
@@ -120,8 +122,9 @@ save your partitions.
|
|||||||
|
|
||||||
.B gdisk
|
.B gdisk
|
||||||
is a text-mode menu-driven program for creation and manipulation of
|
is a text-mode menu-driven program for creation and manipulation of
|
||||||
partition tables. It will automatically convert an MBR partition table to
|
partition tables. It will automatically convert an MBR partition table or
|
||||||
GPT format, or will load a GPT partition table. When used with the
|
BSD disklabel stored without an MBR carrier partition to GPT format, or
|
||||||
|
will load a GPT partition table. When used with the
|
||||||
.IR "\-l"
|
.IR "\-l"
|
||||||
command-line option, the program displays the current partition table and
|
command-line option, the program displays the current partition table and
|
||||||
then exits.
|
then exits.
|
||||||
@@ -173,6 +176,13 @@ will note that
|
|||||||
.B "gdisk"
|
.B "gdisk"
|
||||||
lacks the options and limitations associated with CHS geometries.
|
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,
|
Upon start,
|
||||||
.B gdisk
|
.B gdisk
|
||||||
attempts to identify the partition type in use on the specified disk. If it
|
attempts to identify the partition type in use on the specified disk. If it
|
||||||
@@ -180,10 +190,14 @@ finds valid GPT data,
|
|||||||
.B gdisk
|
.B gdisk
|
||||||
will use it. If
|
will use it. If
|
||||||
.B gdisk
|
.B gdisk
|
||||||
finds a valid MBR but no GPT data, it will attempt to convert the MBR into
|
finds a valid MBR or BSD disklabel but no GPT data, it will attempt to
|
||||||
GPT form. Upon exiting with the 'w' option,
|
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
|
.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!"
|
.IR "This action is potentially dangerous!"
|
||||||
Your system may become unbootable, and partition type codes may become
|
Your system may become unbootable, and partition type codes may become
|
||||||
corrupted if the disk uses unrecognized type codes. Boot problems are
|
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
|
occur with its interactive text-mode menus. The main menu provides the
|
||||||
following options:
|
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
|
.TP
|
||||||
.B c
|
.B c
|
||||||
Change the GPT name of a partition. This name is encoded as a UTF-16
|
Change the GPT name of a partition. This name is encoded as a UTF-16
|
||||||
string, but
|
string, but
|
||||||
.B gdisk
|
.B gdisk
|
||||||
supports only ASCII characters as names. For the most part, Linux ignores
|
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
|
.TP
|
||||||
.B d
|
.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.
|
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
|
Note that some partitioning utilities, such as GNU Parted, will sort
|
||||||
partitions whenever they make changes. Such changes will be reflected in
|
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"
|
.IR "/etc/fstab"
|
||||||
if you use this option.
|
if you use this option.
|
||||||
|
|
||||||
|
|||||||
12
gdisk.cc
12
gdisk.cc
@@ -4,6 +4,9 @@
|
|||||||
//
|
//
|
||||||
// by Rod Smith, February 2009
|
// 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 <iostream>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -24,7 +27,7 @@ int main(int argc, char* argv[]) {
|
|||||||
int doMore = 1;
|
int doMore = 1;
|
||||||
char* device = NULL;
|
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 (argc == 2) { // basic usage
|
||||||
if (SizesOK()) {
|
if (SizesOK()) {
|
||||||
@@ -65,9 +68,9 @@ int DoCommand(char* filename, struct GPTData* theGPT) {
|
|||||||
fgets(line, 255, stdin);
|
fgets(line, 255, stdin);
|
||||||
sscanf(line, "%c", &command);
|
sscanf(line, "%c", &command);
|
||||||
switch (command) {
|
switch (command) {
|
||||||
/* case 'b': case 'B':
|
case 'b': case 'B':
|
||||||
GetGUID();
|
theGPT->XFormDisklabel();
|
||||||
break; */
|
break;
|
||||||
case 'c': case 'C':
|
case 'c': case 'C':
|
||||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
||||||
theGPT->SetName(theGPT->GetPartNum());
|
theGPT->SetName(theGPT->GetPartNum());
|
||||||
@@ -125,6 +128,7 @@ int DoCommand(char* filename, struct GPTData* theGPT) {
|
|||||||
} // DoCommand()
|
} // DoCommand()
|
||||||
|
|
||||||
void ShowCommands(void) {
|
void ShowCommands(void) {
|
||||||
|
printf("b\tconvert BSD disklabel partitions\n");
|
||||||
printf("c\tchange a partition's name\n");
|
printf("c\tchange a partition's name\n");
|
||||||
printf("d\tdelete a partition\n");
|
printf("d\tdelete a partition\n");
|
||||||
printf("i\tshow detailed information on a partition\n");
|
printf("i\tshow detailed information on a partition\n");
|
||||||
|
|||||||
617
gpt.cc
617
gpt.cc
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
/* By Rod Smith, January to February, 2009 */
|
/* 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_LIMIT_MACROS
|
||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
@@ -17,6 +20,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
#include "gpt.h"
|
#include "gpt.h"
|
||||||
|
#include "bsd.h"
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
#include "parttypes.h"
|
#include "parttypes.h"
|
||||||
#include "attributes.h"
|
#include "attributes.h"
|
||||||
@@ -39,6 +43,8 @@ GPTData::GPTData(void) {
|
|||||||
secondCrcOk = 0;
|
secondCrcOk = 0;
|
||||||
mainPartsCrcOk = 0;
|
mainPartsCrcOk = 0;
|
||||||
secondPartsCrcOk = 0;
|
secondPartsCrcOk = 0;
|
||||||
|
apmFound = 0;
|
||||||
|
bsdFound = 0;
|
||||||
srand((unsigned int) time(NULL));
|
srand((unsigned int) time(NULL));
|
||||||
SetGPTSize(NUM_GPT_ENTRIES);
|
SetGPTSize(NUM_GPT_ENTRIES);
|
||||||
} // GPTData default constructor
|
} // GPTData default constructor
|
||||||
@@ -54,6 +60,8 @@ GPTData::GPTData(char* filename) {
|
|||||||
secondCrcOk = 0;
|
secondCrcOk = 0;
|
||||||
mainPartsCrcOk = 0;
|
mainPartsCrcOk = 0;
|
||||||
secondPartsCrcOk = 0;
|
secondPartsCrcOk = 0;
|
||||||
|
apmFound = 0;
|
||||||
|
bsdFound = 0;
|
||||||
srand((unsigned int) time(NULL));
|
srand((unsigned int) time(NULL));
|
||||||
LoadPartitions(filename);
|
LoadPartitions(filename);
|
||||||
} // GPTData(char* filename) constructor
|
} // GPTData(char* filename) constructor
|
||||||
@@ -65,8 +73,8 @@ GPTData::~GPTData(void) {
|
|||||||
// Resizes GPT to specified number of entries. Creates a new table if
|
// Resizes GPT to specified number of entries. Creates a new table if
|
||||||
// necessary, copies data if it already exists.
|
// necessary, copies data if it already exists.
|
||||||
int GPTData::SetGPTSize(uint32_t numEntries) {
|
int GPTData::SetGPTSize(uint32_t numEntries) {
|
||||||
struct GPTPartition* newParts;
|
struct GPTPart* newParts;
|
||||||
struct GPTPartition* trash;
|
struct GPTPart* trash;
|
||||||
uint32_t i, high, copyNum;
|
uint32_t i, high, copyNum;
|
||||||
int allOK = 1;
|
int allOK = 1;
|
||||||
|
|
||||||
@@ -79,7 +87,7 @@ int GPTData::SetGPTSize(uint32_t numEntries) {
|
|||||||
printf("to %lu to fill the sector\n", (unsigned long) numEntries);
|
printf("to %lu to fill the sector\n", (unsigned long) numEntries);
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
newParts = (struct GPTPartition*) calloc(numEntries, sizeof (struct GPTPartition));
|
newParts = (GPTPart*) calloc(numEntries, sizeof (GPTPart));
|
||||||
if (newParts != NULL) {
|
if (newParts != NULL) {
|
||||||
if (partitions != NULL) { // existing partitions; copy them over
|
if (partitions != NULL) { // existing partitions; copy them over
|
||||||
GetPartRange(&i, &high);
|
GetPartRange(&i, &high);
|
||||||
@@ -120,22 +128,22 @@ int GPTData::SetGPTSize(uint32_t numEntries) {
|
|||||||
} // GPTData::SetGPTSize()
|
} // GPTData::SetGPTSize()
|
||||||
|
|
||||||
// Checks to see if the GPT tables overrun existing partitions; if they
|
// 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
|
// do, issues a warning but takes no action. Returns number of problems
|
||||||
// if problems were detected.
|
// detected (0 if OK, 1 to 2 if problems).
|
||||||
int GPTData::CheckGPTSize(void) {
|
int GPTData::CheckGPTSize(void) {
|
||||||
uint64_t overlap, firstUsedBlock, lastUsedBlock;
|
uint64_t overlap, firstUsedBlock, lastUsedBlock;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int allOK = 1;
|
int numProbs = 0;
|
||||||
|
|
||||||
// first, locate the first & last used blocks
|
// first, locate the first & last used blocks
|
||||||
firstUsedBlock = UINT64_MAX;
|
firstUsedBlock = UINT64_MAX;
|
||||||
lastUsedBlock = 0;
|
lastUsedBlock = 0;
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if ((partitions[i].firstLBA < firstUsedBlock) &&
|
if ((partitions[i].GetFirstLBA() < firstUsedBlock) &&
|
||||||
(partitions[i].firstLBA != 0))
|
(partitions[i].GetFirstLBA() != 0))
|
||||||
firstUsedBlock = partitions[i].firstLBA;
|
firstUsedBlock = partitions[i].GetFirstLBA();
|
||||||
if (partitions[i].lastLBA > lastUsedBlock)
|
if (partitions[i].GetLastLBA() > lastUsedBlock)
|
||||||
lastUsedBlock = partitions[i].lastLBA;
|
lastUsedBlock = partitions[i].GetLastLBA();
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
// If the disk size is 0 (the default), then it means that various
|
// 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 (diskSize != 0) {
|
||||||
if (mainHeader.firstUsableLBA > firstUsedBlock) {
|
if (mainHeader.firstUsableLBA > firstUsedBlock) {
|
||||||
overlap = mainHeader.firstUsableLBA - firstUsedBlock;
|
overlap = mainHeader.firstUsableLBA - firstUsedBlock;
|
||||||
printf("Warning! Main partition table overlaps the first partition by %lu\n"
|
printf("Warning! Main partition table overlaps the first partition by %lu blocks!\n",
|
||||||
"blocks! Try reducing the partition table size by %lu entries.\n",
|
(unsigned long) overlap);
|
||||||
(unsigned long) overlap, (unsigned long) (overlap * 4));
|
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");
|
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
|
} // Problem at start of disk
|
||||||
if (mainHeader.lastUsableLBA < lastUsedBlock) {
|
if (mainHeader.lastUsableLBA < lastUsedBlock) {
|
||||||
overlap = lastUsedBlock - mainHeader.lastUsableLBA;
|
overlap = lastUsedBlock - mainHeader.lastUsableLBA;
|
||||||
printf("Warning! Secondary partition table overlaps the last partition by %lu\n"
|
printf("Warning! Secondary partition table overlaps the last partition by %lu blocks\n",
|
||||||
"blocks! Try reducing the partition table size by %lu entries.\n",
|
(unsigned long) overlap);
|
||||||
(unsigned long) overlap, (unsigned long) (overlap * 4));
|
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");
|
printf("(Use the 's' item on the experts' menu.)\n");
|
||||||
allOK = 0;
|
} // if/else
|
||||||
|
numProbs++;
|
||||||
} // Problem at end of disk
|
} // Problem at end of disk
|
||||||
} // if (diskSize != 0)
|
} // if (diskSize != 0)
|
||||||
return allOK;
|
return numProbs;
|
||||||
} // GPTData::CheckGPTSize()
|
} // 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.
|
// Read GPT data from a disk.
|
||||||
int GPTData::LoadPartitions(char* deviceFilename) {
|
int GPTData::LoadPartitions(char* deviceFilename) {
|
||||||
int fd, err;
|
int fd, err;
|
||||||
int allOK = 1, i;
|
int allOK = 1, i;
|
||||||
uint64_t firstBlock, lastBlock;
|
uint64_t firstBlock, lastBlock;
|
||||||
|
BSDData bsdDisklabel;
|
||||||
|
|
||||||
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
|
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
|
||||||
// store disk information....
|
// store disk information....
|
||||||
diskSize = disksize(fd, &err);
|
diskSize = disksize(fd, &err);
|
||||||
blockSize = (uint32_t) GetBlockSize(fd);
|
blockSize = (uint32_t) GetBlockSize(fd);
|
||||||
strcpy(device, deviceFilename);
|
strcpy(device, deviceFilename);
|
||||||
|
PartitionScan(fd); // Check for partition types & print summary
|
||||||
// Read the MBR
|
|
||||||
protectiveMBR.ReadMBRData(fd);
|
|
||||||
|
|
||||||
// Load the GPT data, whether or not it's valid
|
|
||||||
ForceLoadGPTData(fd);
|
|
||||||
|
|
||||||
switch (UseWhichPartitions()) {
|
switch (UseWhichPartitions()) {
|
||||||
case use_mbr:
|
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;
|
break;
|
||||||
case use_gpt:
|
case use_gpt:
|
||||||
break;
|
break;
|
||||||
@@ -197,11 +281,11 @@ int GPTData::LoadPartitions(char* deviceFilename) {
|
|||||||
firstBlock = mainHeader.backupLBA; // start high
|
firstBlock = mainHeader.backupLBA; // start high
|
||||||
lastBlock = 0; // start low
|
lastBlock = 0; // start low
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if ((partitions[i].firstLBA < firstBlock) &&
|
if ((partitions[i].GetFirstLBA() < firstBlock) &&
|
||||||
(partitions[i].firstLBA > 0))
|
(partitions[i].GetFirstLBA() > 0))
|
||||||
firstBlock = partitions[i].firstLBA;
|
firstBlock = partitions[i].GetFirstLBA();
|
||||||
if (partitions[i].lastLBA > lastBlock)
|
if (partitions[i].GetLastLBA() > lastBlock)
|
||||||
lastBlock = partitions[i].lastLBA;
|
lastBlock = partitions[i].GetLastLBA();
|
||||||
} // for
|
} // for
|
||||||
} // if
|
} // if
|
||||||
CheckGPTSize();
|
CheckGPTSize();
|
||||||
@@ -347,13 +431,23 @@ WhichToUse GPTData::UseWhichPartitions(void) {
|
|||||||
which = use_mbr;
|
which = use_mbr;
|
||||||
} // if
|
} // 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)) {
|
if ((state == gpt_valid) && (mbrState == gpt)) {
|
||||||
printf("Found valid GPT with protective MBR; using GPT.\n");
|
printf("Found valid GPT with protective MBR; using GPT.\n");
|
||||||
which = use_gpt;
|
which = use_gpt;
|
||||||
} // if
|
} // if
|
||||||
if ((state == gpt_valid) && (mbrState == hybrid)) {
|
if ((state == gpt_valid) && (mbrState == hybrid)) {
|
||||||
printf("Found valid GPT with hybrid MBR; using GPT.\n");
|
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;
|
which = use_gpt;
|
||||||
} // if
|
} // if
|
||||||
if ((state == gpt_valid) && (mbrState == invalid)) {
|
if ((state == gpt_valid) && (mbrState == invalid)) {
|
||||||
@@ -445,7 +539,7 @@ int GPTData::GetPartRange(uint32_t *low, uint32_t *high) {
|
|||||||
*high = 0;
|
*high = 0;
|
||||||
if (mainHeader.numParts > 0) { // only try if partition table exists...
|
if (mainHeader.numParts > 0) { // only try if partition table exists...
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
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
|
*high = i; // since we're counting up, set the high value
|
||||||
// Set the low value only if it's not yet found...
|
// Set the low value only if it's not yet found...
|
||||||
if (*low == (mainHeader.numParts + 1)) *low = i;
|
if (*low == (mainHeader.numParts + 1)) *low = i;
|
||||||
@@ -481,20 +575,7 @@ void GPTData::DisplayGPTData(void) {
|
|||||||
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
|
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
|
||||||
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
|
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if (partitions[i].firstLBA != 0) {
|
partitions[i].ShowSummary(i, blockSize, sizeInSI);
|
||||||
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
|
|
||||||
} // for
|
} // for
|
||||||
} // GPTData::DisplayGPTData()
|
} // GPTData::DisplayGPTData()
|
||||||
|
|
||||||
@@ -514,33 +595,8 @@ void GPTData::ShowDetails(void) {
|
|||||||
|
|
||||||
// Show detailed information on the specified partition
|
// Show detailed information on the specified partition
|
||||||
void GPTData::ShowPartDetails(uint32_t partNum) {
|
void GPTData::ShowPartDetails(uint32_t partNum) {
|
||||||
char temp[255];
|
if (partitions[partNum].GetFirstLBA() != 0) {
|
||||||
int i;
|
partitions[partNum].ShowDetails(blockSize);
|
||||||
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");
|
|
||||||
} else {
|
} else {
|
||||||
printf("Partition #%d does not exist.", (int) (partNum + 1));
|
printf("Partition #%d does not exist.", (int) (partNum + 1));
|
||||||
} // if
|
} // if
|
||||||
@@ -553,7 +609,7 @@ void GPTData::CreatePartition(void) {
|
|||||||
int partNum, firstFreePart = 0;
|
int partNum, firstFreePart = 0;
|
||||||
|
|
||||||
// Find first free partition...
|
// Find first free partition...
|
||||||
while (partitions[firstFreePart].firstLBA != 0) {
|
while (partitions[firstFreePart].GetFirstLBA() != 0) {
|
||||||
firstFreePart++;
|
firstFreePart++;
|
||||||
} // while
|
} // while
|
||||||
|
|
||||||
@@ -567,9 +623,9 @@ void GPTData::CreatePartition(void) {
|
|||||||
mainHeader.numParts, firstFreePart + 1);
|
mainHeader.numParts, firstFreePart + 1);
|
||||||
partNum = GetNumber(firstFreePart + 1, mainHeader.numParts,
|
partNum = GetNumber(firstFreePart + 1, mainHeader.numParts,
|
||||||
firstFreePart + 1, prompt) - 1;
|
firstFreePart + 1, prompt) - 1;
|
||||||
if (partitions[partNum].firstLBA != 0)
|
if (partitions[partNum].GetFirstLBA() != 0)
|
||||||
printf("partition %d is in use.\n", partNum + 1);
|
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...
|
// Get first block for new partition...
|
||||||
sprintf(prompt, "First sector (%llu-%llu, default = %llu): ", firstBlock,
|
sprintf(prompt, "First sector (%llu-%llu, default = %llu): ", firstBlock,
|
||||||
@@ -588,14 +644,12 @@ void GPTData::CreatePartition(void) {
|
|||||||
} while (IsFree(sector) == 0);
|
} while (IsFree(sector) == 0);
|
||||||
lastBlock = sector;
|
lastBlock = sector;
|
||||||
|
|
||||||
partitions[partNum].firstLBA = firstBlock;
|
partitions[partNum].SetFirstLBA(firstBlock);
|
||||||
partitions[partNum].lastLBA = lastBlock;
|
partitions[partNum].SetLastLBA(lastBlock);
|
||||||
|
|
||||||
// rand() is only 32 bits on 32-bit systems, so multiply together to
|
partitions[partNum].SetUniqueGUID(1);
|
||||||
// fill a 64-bit value.
|
partitions[partNum].ChangeType();
|
||||||
partitions[partNum].uniqueGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
|
partitions[partNum].SetName((unsigned char*) partitions[partNum].GetNameType(prompt));
|
||||||
partitions[partNum].uniqueGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
|
|
||||||
ChangeGPTType(&partitions[partNum]);
|
|
||||||
} else {
|
} else {
|
||||||
printf("No free sectors available\n");
|
printf("No free sectors available\n");
|
||||||
} // if/else
|
} // if/else
|
||||||
@@ -610,11 +664,11 @@ void GPTData::DeletePartition(void) {
|
|||||||
if (GetPartRange(&low, &high) > 0) {
|
if (GetPartRange(&low, &high) > 0) {
|
||||||
sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
|
sprintf(prompt, "Partition number (%d-%d): ", low + 1, high + 1);
|
||||||
partNum = GetNumber(low + 1, high + 1, low, prompt);
|
partNum = GetNumber(low + 1, high + 1, low, prompt);
|
||||||
BlankPartition(&partitions[partNum - 1]);
|
partitions[partNum - 1].BlankPartition();
|
||||||
} else {
|
} else {
|
||||||
printf("No partitions\n");
|
printf("No partitions\n");
|
||||||
} // if/else
|
} // if/else
|
||||||
} // GPTData::DeletePartition
|
} // GPTData::DeletePartition()
|
||||||
|
|
||||||
// Find the first available block after the starting point; returns 0 if
|
// Find the first available block after the starting point; returns 0 if
|
||||||
// there are no available blocks left
|
// there are no available blocks left
|
||||||
@@ -638,9 +692,9 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) {
|
|||||||
do {
|
do {
|
||||||
firstMoved = 0;
|
firstMoved = 0;
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if ((first >= partitions[i].firstLBA) &&
|
if ((first >= partitions[i].GetFirstLBA()) &&
|
||||||
(first <= partitions[i].lastLBA)) { // in existing part.
|
(first <= partitions[i].GetLastLBA())) { // in existing part.
|
||||||
first = partitions[i].lastLBA + 1;
|
first = partitions[i].GetLastLBA() + 1;
|
||||||
firstMoved = 1;
|
firstMoved = 1;
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
@@ -668,9 +722,9 @@ uint64_t GPTData::FindLastAvailable(uint64_t start) {
|
|||||||
do {
|
do {
|
||||||
lastMoved = 0;
|
lastMoved = 0;
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if ((last >= partitions[i].firstLBA) &&
|
if ((last >= partitions[i].GetFirstLBA()) &&
|
||||||
(last <= partitions[i].lastLBA)) { // in existing part.
|
(last <= partitions[i].GetLastLBA())) { // in existing part.
|
||||||
last = partitions[i].firstLBA - 1;
|
last = partitions[i].GetFirstLBA() - 1;
|
||||||
lastMoved = 1;
|
lastMoved = 1;
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
@@ -687,9 +741,9 @@ uint64_t GPTData::FindLastInFree(uint64_t start) {
|
|||||||
|
|
||||||
nearestStart = mainHeader.lastUsableLBA;
|
nearestStart = mainHeader.lastUsableLBA;
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if ((nearestStart > partitions[i].firstLBA) &&
|
if ((nearestStart > partitions[i].GetFirstLBA()) &&
|
||||||
(partitions[i].firstLBA > start)) {
|
(partitions[i].GetFirstLBA() > start)) {
|
||||||
nearestStart = partitions[i].firstLBA - 1;
|
nearestStart = partitions[i].GetFirstLBA() - 1;
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
return (nearestStart);
|
return (nearestStart);
|
||||||
@@ -701,8 +755,8 @@ int GPTData::IsFree(uint64_t sector) {
|
|||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if ((sector >= partitions[i].firstLBA) &&
|
if ((sector >= partitions[i].GetFirstLBA()) &&
|
||||||
(sector <= partitions[i].lastLBA)) {
|
(sector <= partitions[i].GetLastLBA())) {
|
||||||
isFree = 0;
|
isFree = 0;
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
@@ -713,10 +767,11 @@ int GPTData::IsFree(uint64_t sector) {
|
|||||||
return (isFree);
|
return (isFree);
|
||||||
} // GPTData::IsFree()
|
} // GPTData::IsFree()
|
||||||
|
|
||||||
int GPTData::XFormPartitions(MBRData* origParts) {
|
int GPTData::XFormPartitions(void) {
|
||||||
int i, j;
|
int i, numToConvert;
|
||||||
int numToConvert;
|
|
||||||
uint8_t origType;
|
uint8_t origType;
|
||||||
|
struct newGUID;
|
||||||
|
char name[NAME_SIZE];
|
||||||
|
|
||||||
// Clear out old data & prepare basics....
|
// Clear out old data & prepare basics....
|
||||||
ClearGPTData();
|
ClearGPTData();
|
||||||
@@ -728,24 +783,12 @@ int GPTData::XFormPartitions(MBRData* origParts) {
|
|||||||
numToConvert = mainHeader.numParts;
|
numToConvert = mainHeader.numParts;
|
||||||
|
|
||||||
for (i = 0; i < numToConvert; i++) {
|
for (i = 0; i < numToConvert; i++) {
|
||||||
origType = origParts->GetType(i);
|
origType = protectiveMBR.GetType(i);
|
||||||
|
// don't waste CPU time trying to convert extended, hybrid protective, or
|
||||||
// don't convert extended, hybrid protective, or null (non-existent) partitions
|
// null (non-existent) partitions
|
||||||
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
|
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
|
||||||
(origType != 0x00) && (origType != 0xEE)) {
|
(origType != 0x00) && (origType != 0xEE))
|
||||||
partitions[i].firstLBA = (uint64_t) origParts->GetFirstSector(i);
|
partitions[i] = protectiveMBR.AsGPT(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
|
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
// Convert MBR into protective MBR
|
// Convert MBR into protective MBR
|
||||||
@@ -756,18 +799,87 @@ int GPTData::XFormPartitions(MBRData* origParts) {
|
|||||||
mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1;
|
mainCrcOk = secondCrcOk = mainPartsCrcOk = secondPartsCrcOk = 1;
|
||||||
|
|
||||||
return (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
|
// Sort the GPT entries, eliminating gaps and making for a logical
|
||||||
// ordering. Relies on QuickSortGPT() for the bulk of the work
|
// ordering. Relies on QuickSortGPT() for the bulk of the work
|
||||||
void GPTData::SortGPT(void) {
|
void GPTData::SortGPT(void) {
|
||||||
int i, lastPart = 0;
|
int i, lastPart = 0;
|
||||||
struct GPTPartition temp;
|
GPTPart temp;
|
||||||
|
|
||||||
// First, find the last partition with data, so as not to
|
// First, find the last partition with data, so as not to
|
||||||
// spend needless time sorting empty entries....
|
// spend needless time sorting empty entries....
|
||||||
for (i = 0; i < GPT_SIZE; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
if (partitions[i].firstLBA > 0)
|
if (partitions[i].GetFirstLBA() > 0)
|
||||||
lastPart = i;
|
lastPart = i;
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
@@ -775,7 +887,7 @@ void GPTData::SortGPT(void) {
|
|||||||
// in the Quicksort function....
|
// in the Quicksort function....
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < lastPart) {
|
while (i < lastPart) {
|
||||||
if (partitions[i].firstLBA == 0) {
|
if (partitions[i].GetFirstLBA() == 0) {
|
||||||
temp = partitions[i];
|
temp = partitions[i];
|
||||||
partitions[i] = partitions[lastPart];
|
partitions[i] = partitions[lastPart];
|
||||||
partitions[lastPart] = temp;
|
partitions[lastPart] = temp;
|
||||||
@@ -788,56 +900,12 @@ void GPTData::SortGPT(void) {
|
|||||||
QuickSortGPT(partitions, 0, lastPart);
|
QuickSortGPT(partitions, 0, lastPart);
|
||||||
} // GPTData::SortGPT()
|
} // GPTData::SortGPT()
|
||||||
|
|
||||||
// Recursive quick sort algorithm for GPT partitions. Note that if there
|
|
||||||
// are any empties in the specified range, they'll be sorted to the
|
|
||||||
// start, resulting in a sorted set of partitions that begins with
|
|
||||||
// partition 2, 3, or higher.
|
|
||||||
void 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
|
// Blank the partition array
|
||||||
void GPTData::BlankPartitions(void) {
|
void GPTData::BlankPartitions(void) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
BlankPartition(&partitions[i]);
|
partitions[i].BlankPartition();
|
||||||
} // for
|
} // for
|
||||||
} // GPTData::BlankPartitions()
|
} // GPTData::BlankPartitions()
|
||||||
|
|
||||||
@@ -877,49 +945,16 @@ int GPTData::ClearGPTData(void) {
|
|||||||
|
|
||||||
// Blank out the partitions array....
|
// Blank out the partitions array....
|
||||||
BlankPartitions();
|
BlankPartitions();
|
||||||
|
|
||||||
|
// Flag all CRCs as being OK....
|
||||||
|
mainCrcOk = 1;
|
||||||
|
secondCrcOk = 1;
|
||||||
|
mainPartsCrcOk = 1;
|
||||||
|
secondPartsCrcOk = 1;
|
||||||
|
|
||||||
return (goOn);
|
return (goOn);
|
||||||
} // GPTData::ClearGPTData()
|
} // 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
|
// Prompt user for a partition number, then change its type code
|
||||||
// using ChangeGPTType(struct GPTPartition*) function.
|
// using ChangeGPTType(struct GPTPartition*) function.
|
||||||
void GPTData::ChangePartType(void) {
|
void GPTData::ChangePartType(void) {
|
||||||
@@ -928,7 +963,7 @@ void GPTData::ChangePartType(void) {
|
|||||||
|
|
||||||
if (GetPartRange(&low, &high) > 0) {
|
if (GetPartRange(&low, &high) > 0) {
|
||||||
partNum = GetPartNum();
|
partNum = GetPartNum();
|
||||||
ChangeGPTType(&partitions[partNum]);
|
partitions[partNum].ChangeType();
|
||||||
} else {
|
} else {
|
||||||
printf("No partitions\n");
|
printf("No partitions\n");
|
||||||
} // if/else
|
} // if/else
|
||||||
@@ -947,51 +982,20 @@ uint32_t GPTData::GetPartNum(void) {
|
|||||||
return (partNum - 1);
|
return (partNum - 1);
|
||||||
} // GPTData::GetPartNum()
|
} // GPTData::GetPartNum()
|
||||||
|
|
||||||
// Prompt user for attributes to change on the specified partition
|
|
||||||
// and change them.
|
|
||||||
void GPTData::SetAttributes(uint32_t partNum) {
|
void GPTData::SetAttributes(uint32_t partNum) {
|
||||||
Attributes theAttr;
|
Attributes theAttr;
|
||||||
|
|
||||||
theAttr.SetAttributes(partitions[partNum].attributes);
|
theAttr.SetAttributes(partitions[partNum].GetAttributes());
|
||||||
theAttr.DisplayAttributes();
|
theAttr.DisplayAttributes();
|
||||||
theAttr.ChangeAttributes();
|
theAttr.ChangeAttributes();
|
||||||
partitions[partNum].attributes = theAttr.GetAttributes();
|
partitions[partNum].SetAttributes(theAttr.GetAttributes());
|
||||||
} // GPTData::SetAttributes()
|
} // 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) {
|
void GPTData::SetName(uint32_t partNum, char* theName) {
|
||||||
char newName[NAME_SIZE]; // New name
|
if ((partNum >= 0) && (partNum < mainHeader.numParts))
|
||||||
int i;
|
if (partitions[partNum].GetFirstLBA() > 0)
|
||||||
|
partitions[partNum].SetName((unsigned char*) theName);
|
||||||
// Blank out new name string, just to be on the safe side....
|
} // GPTData::SetName
|
||||||
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()
|
|
||||||
|
|
||||||
// Set the disk GUID to the specified value. Note that the header CRCs must
|
// Set the disk GUID to the specified value. Note that the header CRCs must
|
||||||
// be recomputed after calling this function.
|
// be recomputed after calling this function.
|
||||||
@@ -1007,8 +1011,8 @@ int GPTData::SetPartitionGUID(uint32_t pn, GUIDData theGUID) {
|
|||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
if (pn < mainHeader.numParts) {
|
if (pn < mainHeader.numParts) {
|
||||||
if (partitions[pn].firstLBA != UINT64_C(0)) {
|
if (partitions[pn].GetFirstLBA() != UINT64_C(0)) {
|
||||||
partitions[pn].uniqueGUID = theGUID;
|
partitions[pn].SetUniqueGUID(theGUID);
|
||||||
retval = 1;
|
retval = 1;
|
||||||
} // if
|
} // if
|
||||||
} // if
|
} // if
|
||||||
@@ -1024,8 +1028,8 @@ int GPTData::CheckHeaderValidity(void) {
|
|||||||
|
|
||||||
if (mainHeader.signature != GPT_SIGNATURE) {
|
if (mainHeader.signature != GPT_SIGNATURE) {
|
||||||
valid -= 1;
|
valid -= 1;
|
||||||
printf("Main GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
|
// printf("Main GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
|
||||||
(unsigned long long) mainHeader.signature, (unsigned long long) GPT_SIGNATURE);
|
// (unsigned long long) mainHeader.signature, (unsigned long long) GPT_SIGNATURE);
|
||||||
} else if ((mainHeader.revision != 0x00010000) && valid) {
|
} else if ((mainHeader.revision != 0x00010000) && valid) {
|
||||||
valid -= 1;
|
valid -= 1;
|
||||||
printf("Unsupported GPT version in main header; read 0x%08lX, should be\n0x%08lX\n",
|
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) {
|
if (secondHeader.signature != GPT_SIGNATURE) {
|
||||||
valid -= 2;
|
valid -= 2;
|
||||||
printf("Secondary GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
|
// printf("Secondary GPT signature invalid; read 0x%016llX, should be\n0x%016llX\n",
|
||||||
(unsigned long long) secondHeader.signature, (unsigned long long) GPT_SIGNATURE);
|
// (unsigned long long) secondHeader.signature, (unsigned long long) GPT_SIGNATURE);
|
||||||
} else if ((secondHeader.revision != 0x00010000) && valid) {
|
} else if ((secondHeader.revision != 0x00010000) && valid) {
|
||||||
valid -= 2;
|
valid -= 2;
|
||||||
printf("Unsupported GPT version in backup header; read 0x%08lX, should be\n0x%08lX\n",
|
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) &&
|
if ((protectiveMBR.GetValidity() == invalid) &&
|
||||||
(((mainHeader.signature << 32) == APM_SIGNATURE1) ||
|
(((mainHeader.signature << 32) == APM_SIGNATURE1) ||
|
||||||
(mainHeader.signature << 32) == APM_SIGNATURE2)) {
|
(mainHeader.signature << 32) == APM_SIGNATURE2)) {
|
||||||
printf("\n*******************************************************************\n");
|
apmFound = 1; // Will display warning message later
|
||||||
printf("This disk appears to contain an Apple-format (APM) partition table!\n");
|
|
||||||
printf("*******************************************************************\n\n\a");
|
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
@@ -1064,7 +1066,7 @@ int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
|||||||
// computation to be valid
|
// computation to be valid
|
||||||
oldCRC = header->headerCRC;
|
oldCRC = header->headerCRC;
|
||||||
if (IsLittleEndian() == 0)
|
if (IsLittleEndian() == 0)
|
||||||
ReverseBytes((char*) &oldCRC, 4);
|
ReverseBytes(&oldCRC, 4);
|
||||||
header->headerCRC = UINT32_C(0);
|
header->headerCRC = UINT32_C(0);
|
||||||
|
|
||||||
// Initialize CRC functions...
|
// Initialize CRC functions...
|
||||||
@@ -1091,13 +1093,13 @@ void GPTData::RecomputeCRCs(void) {
|
|||||||
// Compute CRC of partition tables & store in main and secondary headers
|
// Compute CRC of partition tables & store in main and secondary headers
|
||||||
trueNumParts = mainHeader.numParts;
|
trueNumParts = mainHeader.numParts;
|
||||||
if (littleEndian == 0)
|
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);
|
crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
|
||||||
mainHeader.partitionEntriesCRC = crc;
|
mainHeader.partitionEntriesCRC = crc;
|
||||||
secondHeader.partitionEntriesCRC = crc;
|
secondHeader.partitionEntriesCRC = crc;
|
||||||
if (littleEndian == 0) {
|
if (littleEndian == 0) {
|
||||||
ReverseBytes((char*) &mainHeader.partitionEntriesCRC, 4);
|
ReverseBytes(&mainHeader.partitionEntriesCRC, 4);
|
||||||
ReverseBytes((char*) &secondHeader.partitionEntriesCRC, 4);
|
ReverseBytes(&secondHeader.partitionEntriesCRC, 4);
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// Zero out GPT tables' own CRCs (required for correct computation)
|
// 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...
|
// Compute & store CRCs of main & secondary headers...
|
||||||
crc = chksum_crc32((unsigned char*) &mainHeader, HEADER_SIZE);
|
crc = chksum_crc32((unsigned char*) &mainHeader, HEADER_SIZE);
|
||||||
if (littleEndian == 0)
|
if (littleEndian == 0)
|
||||||
ReverseBytes((char*) &crc, 4);
|
ReverseBytes(&crc, 4);
|
||||||
mainHeader.headerCRC = crc;
|
mainHeader.headerCRC = crc;
|
||||||
crc = chksum_crc32((unsigned char*) &secondHeader, HEADER_SIZE);
|
crc = chksum_crc32((unsigned char*) &secondHeader, HEADER_SIZE);
|
||||||
if (littleEndian == 0)
|
if (littleEndian == 0)
|
||||||
ReverseBytes((char*) &crc, 4);
|
ReverseBytes(&crc, 4);
|
||||||
secondHeader.headerCRC = crc;
|
secondHeader.headerCRC = crc;
|
||||||
} // GPTData::RecomputeCRCs()
|
} // GPTData::RecomputeCRCs()
|
||||||
|
|
||||||
@@ -1213,19 +1215,22 @@ int GPTData::Verify(void) {
|
|||||||
// Check for overlapping partitions....
|
// Check for overlapping partitions....
|
||||||
for (i = 1; i < mainHeader.numParts; i++) {
|
for (i = 1; i < mainHeader.numParts; i++) {
|
||||||
for (j = 0; j < i; j++) {
|
for (j = 0; j < i; j++) {
|
||||||
if (TheyOverlap(&partitions[i], &partitions[j])) {
|
if (partitions[i].DoTheyOverlap(&partitions[j])) {
|
||||||
problems++;
|
problems++;
|
||||||
printf("\nProblem: partitions %d and %d overlap:\n", i + 1, j + 1);
|
printf("\nProblem: partitions %d and %d overlap:\n", i + 1, j + 1);
|
||||||
printf(" Partition %d: %llu to %llu\n", i,
|
printf(" Partition %d: %llu to %llu\n", i,
|
||||||
(unsigned long long) partitions[i].firstLBA,
|
(unsigned long long) partitions[i].GetFirstLBA(),
|
||||||
(unsigned long long) partitions[i].lastLBA);
|
(unsigned long long) partitions[i].GetLastLBA());
|
||||||
printf(" Partition %d: %llu to %llu\n", j,
|
printf(" Partition %d: %llu to %llu\n", j,
|
||||||
(unsigned long long) partitions[j].firstLBA,
|
(unsigned long long) partitions[j].GetFirstLBA(),
|
||||||
(unsigned long long) partitions[j].lastLBA);
|
(unsigned long long) partitions[j].GetLastLBA());
|
||||||
} // if
|
} // if
|
||||||
} // for j...
|
} // for j...
|
||||||
} // for i...
|
} // 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
|
// Now compute available space, but only if no problems found, since
|
||||||
// problems could affect the results
|
// problems could affect the results
|
||||||
if (problems == 0) {
|
if (problems == 0) {
|
||||||
@@ -1382,23 +1387,23 @@ void GPTData::MakeHybrid(void) {
|
|||||||
j = partNums[i] - 1;
|
j = partNums[i] - 1;
|
||||||
printf("\nCreating entry for partition #%d\n", j + 1);
|
printf("\nCreating entry for partition #%d\n", j + 1);
|
||||||
if ((j >= 0) && (j < mainHeader.numParts)) {
|
if ((j >= 0) && (j < mainHeader.numParts)) {
|
||||||
if (partitions[j].lastLBA < UINT32_MAX) {
|
if (partitions[j].GetLastLBA() < UINT32_MAX) {
|
||||||
do {
|
do {
|
||||||
printf("Enter an MBR hex code (default %02X): ",
|
printf("Enter an MBR hex code (default %02X): ",
|
||||||
typeHelper.GUIDToID(partitions[j].partitionType) / 256);
|
typeHelper.GUIDToID(partitions[j].GetType()) / 256);
|
||||||
fgets(line, 255, stdin);
|
fgets(line, 255, stdin);
|
||||||
sscanf(line, "%x", &typeCode);
|
sscanf(line, "%x", &typeCode);
|
||||||
if (line[0] == '\n')
|
if (line[0] == '\n')
|
||||||
typeCode = typeHelper.GUIDToID(partitions[j].partitionType) / 256;
|
typeCode = partitions[j].GetHexType() / 256;
|
||||||
} while ((typeCode <= 0) || (typeCode > 255));
|
} while ((typeCode <= 0) || (typeCode > 255));
|
||||||
printf("Set the bootable flag? ");
|
printf("Set the bootable flag? ");
|
||||||
bootable = (GetYN() == 'Y');
|
bootable = (GetYN() == 'Y');
|
||||||
length = partitions[j].lastLBA - partitions[j].firstLBA + UINT64_C(1);
|
length = partitions[j].GetLengthLBA();
|
||||||
if (eeFirst == 'Y')
|
if (eeFirst == 'Y')
|
||||||
mbrNum = i + 1;
|
mbrNum = i + 1;
|
||||||
else
|
else
|
||||||
mbrNum = i;
|
mbrNum = i;
|
||||||
protectiveMBR.MakePart(mbrNum, (uint32_t) partitions[j].firstLBA,
|
protectiveMBR.MakePart(mbrNum, (uint32_t) partitions[j].GetFirstLBA(),
|
||||||
(uint32_t) length, typeCode, bootable);
|
(uint32_t) length, typeCode, bootable);
|
||||||
} else { // partition out of range
|
} else { // partition out of range
|
||||||
printf("Partition %d ends beyond the 2TiB limit of MBR partitions; omitting it.\n",
|
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....
|
// First do some final sanity checks....
|
||||||
// Is there enough space to hold the GPT headers and partition tables,
|
// Is there enough space to hold the GPT headers and partition tables,
|
||||||
// given the partition sizes?
|
// given the partition sizes?
|
||||||
if (CheckGPTSize() == 0) {
|
if (CheckGPTSize() > 0) {
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
@@ -1488,14 +1493,14 @@ int GPTData::SaveGPTData(void) {
|
|||||||
// Check for overlapping partitions....
|
// Check for overlapping partitions....
|
||||||
for (i = 1; i < mainHeader.numParts; i++) {
|
for (i = 1; i < mainHeader.numParts; i++) {
|
||||||
for (j = 0; j < i; j++) {
|
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, "\Error: partitions %d and %d overlap:\n", i + 1, j + 1);
|
||||||
fprintf(stderr, " Partition %d: %llu to %llu\n", i,
|
fprintf(stderr, " Partition %d: %llu to %llu\n", i,
|
||||||
(unsigned long long) partitions[i].firstLBA,
|
(unsigned long long) partitions[i].GetFirstLBA(),
|
||||||
(unsigned long long) partitions[i].lastLBA);
|
(unsigned long long) partitions[i].GetLastLBA());
|
||||||
fprintf(stderr, " Partition %d: %llu to %llu\n", j,
|
fprintf(stderr, " Partition %d: %llu to %llu\n", j,
|
||||||
(unsigned long long) partitions[j].firstLBA,
|
(unsigned long long) partitions[j].GetFirstLBA(),
|
||||||
(unsigned long long) partitions[j].lastLBA);
|
(unsigned long long) partitions[j].GetLastLBA());
|
||||||
fprintf(stderr, "Aborting write operation!\n");
|
fprintf(stderr, "Aborting write operation!\n");
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
@@ -1582,12 +1587,18 @@ int GPTData::SaveGPTData(void) {
|
|||||||
* it definitely will get things on disk though:
|
* it definitely will get things on disk though:
|
||||||
* http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
|
* http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
|
||||||
i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
|
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
|
#else
|
||||||
sleep(2);
|
sleep(2);
|
||||||
i = ioctl(fd, BLKRRPART);
|
i = ioctl(fd, BLKRRPART);
|
||||||
if (i)
|
if (i)
|
||||||
printf("Warning: The kernel is still using the old partition table.\n"
|
printf("Warning: The kernel is still using the old partition table.\n"
|
||||||
"The new table will be used at the next reboot.\n");
|
"The new table will be used at the next reboot.\n");
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
@@ -1691,7 +1702,7 @@ int GPTData::LoadGPTBackup(char* filename) {
|
|||||||
littleEndian = 0;
|
littleEndian = 0;
|
||||||
|
|
||||||
// Let the MBRData class load the saved MBR...
|
// 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
|
// Load the main GPT header, check its vaility, and set the GPT
|
||||||
// size based on the data
|
// size based on the data
|
||||||
@@ -1815,22 +1826,22 @@ int GPTData::DestroyGPT(void) {
|
|||||||
} // GPTData::DestroyGPT()
|
} // GPTData::DestroyGPT()
|
||||||
|
|
||||||
void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
|
void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
|
||||||
ReverseBytes((char*) &header->signature, 8);
|
ReverseBytes(&header->signature, 8);
|
||||||
ReverseBytes((char*) &header->revision, 4);
|
ReverseBytes(&header->revision, 4);
|
||||||
ReverseBytes((char*) &header->headerSize, 4);
|
ReverseBytes(&header->headerSize, 4);
|
||||||
ReverseBytes((char*) &header->headerCRC, 4);
|
ReverseBytes(&header->headerCRC, 4);
|
||||||
ReverseBytes((char*) &header->reserved, 4);
|
ReverseBytes(&header->reserved, 4);
|
||||||
ReverseBytes((char*) &header->currentLBA, 8);
|
ReverseBytes(&header->currentLBA, 8);
|
||||||
ReverseBytes((char*) &header->backupLBA, 8);
|
ReverseBytes(&header->backupLBA, 8);
|
||||||
ReverseBytes((char*) &header->firstUsableLBA, 8);
|
ReverseBytes(&header->firstUsableLBA, 8);
|
||||||
ReverseBytes((char*) &header->lastUsableLBA, 8);
|
ReverseBytes(&header->lastUsableLBA, 8);
|
||||||
ReverseBytes((char*) &header->partitionEntriesLBA, 8);
|
ReverseBytes(&header->partitionEntriesLBA, 8);
|
||||||
ReverseBytes((char*) &header->numParts, 4);
|
ReverseBytes(&header->numParts, 4);
|
||||||
ReverseBytes((char*) &header->sizeOfPartitionEntries, 4);
|
ReverseBytes(&header->sizeOfPartitionEntries, 4);
|
||||||
ReverseBytes((char*) &header->partitionEntriesCRC, 4);
|
ReverseBytes(&header->partitionEntriesCRC, 4);
|
||||||
ReverseBytes((char*) header->reserved2, GPT_RESERVED);
|
ReverseBytes(&header->reserved2, GPT_RESERVED);
|
||||||
ReverseBytes((char*) &header->diskGUID.data1, 8);
|
ReverseBytes(&header->diskGUID.data1, 8);
|
||||||
ReverseBytes((char*) &header->diskGUID.data2, 8);
|
ReverseBytes(&header->diskGUID.data2, 8);
|
||||||
} // GPTData::ReverseHeaderBytes()
|
} // GPTData::ReverseHeaderBytes()
|
||||||
|
|
||||||
// IMPORTANT NOTE: This function requires non-reversed mainHeader
|
// 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");
|
"data corruption or a misplaced call to this function.\n");
|
||||||
} // if signature mismatch....
|
} // if signature mismatch....
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
ReverseBytes((char*) &partitions[i].partitionType.data1, 8);
|
partitions[i].ReversePartBytes();
|
||||||
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);
|
|
||||||
} // for
|
} // for
|
||||||
} // GPTData::ReversePartitionBytes()
|
} // GPTData::ReversePartitionBytes()
|
||||||
|
|
||||||
@@ -1886,15 +1891,19 @@ int SizesOK(void) {
|
|||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
if (sizeof(struct MBRRecord) != 16) {
|
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;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
if (sizeof(struct EBRRecord) != 512) {
|
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;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
if (sizeof(struct GPTHeader) != 512) {
|
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;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
// Determine endianness; set allOK = 0 if running on big-endian hardware
|
// Determine endianness; set allOK = 0 if running on big-endian hardware
|
||||||
|
|||||||
49
gpt.h
49
gpt.h
@@ -1,34 +1,21 @@
|
|||||||
/* gpt.h -- GPT and data structure definitions, types, and
|
/* gpt.h -- GPT and data structure definitions, types, and
|
||||||
functions */
|
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 <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
#include "parttypes.h"
|
#include "parttypes.h"
|
||||||
#include "mbr.h"
|
#include "mbr.h"
|
||||||
|
#include "bsd.h"
|
||||||
|
#include "gptpart.h"
|
||||||
|
|
||||||
#ifndef __GPTSTRUCTS
|
#ifndef __GPTSTRUCTS
|
||||||
#define __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;
|
using namespace std;
|
||||||
|
|
||||||
@@ -42,7 +29,7 @@ using namespace std;
|
|||||||
enum GPTValidity {gpt_valid, gpt_corrupt, gpt_invalid};
|
enum GPTValidity {gpt_valid, gpt_corrupt, gpt_invalid};
|
||||||
|
|
||||||
// Which set of partition data to use
|
// 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
|
// Header (first 512 bytes) of GPT table
|
||||||
struct GPTHeader {
|
struct GPTHeader {
|
||||||
@@ -63,20 +50,11 @@ struct GPTHeader {
|
|||||||
unsigned char reserved2[GPT_RESERVED];
|
unsigned char reserved2[GPT_RESERVED];
|
||||||
}; // struct GPTHeader
|
}; // 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
|
// Data in GPT format
|
||||||
class GPTData {
|
class GPTData {
|
||||||
protected:
|
protected:
|
||||||
struct GPTHeader mainHeader;
|
struct GPTHeader mainHeader;
|
||||||
struct GPTPartition *partitions;
|
struct GPTPart *partitions;
|
||||||
struct GPTHeader secondHeader;
|
struct GPTHeader secondHeader;
|
||||||
MBRData protectiveMBR;
|
MBRData protectiveMBR;
|
||||||
char device[256]; // device filename
|
char device[256]; // device filename
|
||||||
@@ -87,6 +65,8 @@ protected:
|
|||||||
int secondCrcOk;
|
int secondCrcOk;
|
||||||
int mainPartsCrcOk;
|
int mainPartsCrcOk;
|
||||||
int secondPartsCrcOk;
|
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
|
// uint32_t units; // display units, in multiples of sectors
|
||||||
PartTypes typeHelper;
|
PartTypes typeHelper;
|
||||||
public:
|
public:
|
||||||
@@ -95,6 +75,9 @@ public:
|
|||||||
~GPTData(void);
|
~GPTData(void);
|
||||||
int SetGPTSize(uint32_t numEntries);
|
int SetGPTSize(uint32_t numEntries);
|
||||||
int CheckGPTSize(void);
|
int CheckGPTSize(void);
|
||||||
|
void ShowAPMState(void);
|
||||||
|
void ShowGPTState(void);
|
||||||
|
void PartitionScan(int fd);
|
||||||
int LoadPartitions(char* deviceFilename);
|
int LoadPartitions(char* deviceFilename);
|
||||||
int ForceLoadGPTData(int fd);
|
int ForceLoadGPTData(int fd);
|
||||||
int LoadMainTable(void);
|
int LoadMainTable(void);
|
||||||
@@ -112,7 +95,9 @@ public:
|
|||||||
uint64_t FindLastAvailable(uint64_t start);
|
uint64_t FindLastAvailable(uint64_t start);
|
||||||
uint64_t FindLastInFree(uint64_t start);
|
uint64_t FindLastInFree(uint64_t start);
|
||||||
int IsFree(uint64_t sector);
|
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);
|
void SortGPT(void);
|
||||||
int ClearGPTData(void);
|
int ClearGPTData(void);
|
||||||
void ChangePartType(void);
|
void ChangePartType(void);
|
||||||
@@ -135,6 +120,8 @@ public:
|
|||||||
int SaveGPTBackup(char* filename);
|
int SaveGPTBackup(char* filename);
|
||||||
int LoadGPTBackup(char* filename);
|
int LoadGPTBackup(char* filename);
|
||||||
int DestroyGPT(void); // Returns 1 if user proceeds
|
int DestroyGPT(void); // Returns 1 if user proceeds
|
||||||
|
|
||||||
|
// Endianness functions
|
||||||
void ReverseHeaderBytes(struct GPTHeader* header); // for endianness
|
void ReverseHeaderBytes(struct GPTHeader* header); // for endianness
|
||||||
void ReversePartitionBytes(); // for endianness
|
void ReversePartitionBytes(); // for endianness
|
||||||
|
|
||||||
@@ -150,8 +137,6 @@ public:
|
|||||||
|
|
||||||
// Function prototypes....
|
// Function prototypes....
|
||||||
void BlankPartition(struct GPTPartition* partition);
|
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);
|
int TheyOverlap(struct GPTPartition* first, struct GPTPartition* second);
|
||||||
void ChangeGPTType(struct GPTPartition* part);
|
void ChangeGPTType(struct GPTPartition* part);
|
||||||
int SizesOK(void);
|
int SizesOK(void);
|
||||||
|
|||||||
161
mbr.cc
161
mbr.cc
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
/* By Rod Smith, January to February, 2009 */
|
/* 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_LIMIT_MACROS
|
||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
@@ -118,9 +121,10 @@ int MBRData::ReadMBRData(char* deviceFilename) {
|
|||||||
} // MBRData::ReadMBRData(char* deviceFilename)
|
} // MBRData::ReadMBRData(char* deviceFilename)
|
||||||
|
|
||||||
// Read data from MBR.
|
// Read data from MBR.
|
||||||
void MBRData::ReadMBRData(int fd) {
|
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
||||||
int allOK = 1, i, maxLogicals = 0;
|
int allOK = 1, i, j, maxLogicals = 0;
|
||||||
int err;
|
int err;
|
||||||
|
TempMBR tempMBR;
|
||||||
|
|
||||||
// Clear logical partition array
|
// Clear logical partition array
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
for (i = 0; i < NUM_LOGICALS; i++) {
|
||||||
@@ -136,39 +140,51 @@ void MBRData::ReadMBRData(int fd) {
|
|||||||
logicals[i].lengthLBA = UINT32_C(0);
|
logicals[i].lengthLBA = UINT32_C(0);
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
read(fd, code, 440);
|
err = lseek64(fd, 0, SEEK_SET);
|
||||||
read(fd, &diskSignature, 4);
|
err = read(fd, &tempMBR, 512);
|
||||||
read(fd, &nulls, 2);
|
for (i = 0; i < 440; i++)
|
||||||
read(fd, partitions, 64);
|
code[i] = tempMBR.code[i];
|
||||||
read(fd, &MBRSignature, 2);
|
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
|
// Reverse the byte order, if necessary
|
||||||
if (IsLittleEndian() == 0) {
|
if (IsLittleEndian() == 0) {
|
||||||
ReverseBytes((char*) &diskSignature, 4);
|
ReverseBytes(&diskSignature, 4);
|
||||||
ReverseBytes((char*) &nulls, 2);
|
ReverseBytes(&nulls, 2);
|
||||||
ReverseBytes((char*) &MBRSignature, 2);
|
ReverseBytes(&MBRSignature, 2);
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
ReverseBytes((char*) &partitions[i].firstLBA, 4);
|
ReverseBytes(&partitions[i].firstLBA, 4);
|
||||||
ReverseBytes((char*) &partitions[i].lengthLBA, 4);
|
ReverseBytes(&partitions[i].lengthLBA, 4);
|
||||||
} // for
|
} // for
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
if (MBRSignature != MBR_SIGNATURE) {
|
if (MBRSignature != MBR_SIGNATURE) {
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
state = invalid;
|
state = invalid;
|
||||||
fprintf(stderr, "MBR signature invalid; read 0x%04X, but should be 0x%04X\n",
|
} // if
|
||||||
(unsigned int) MBRSignature, (unsigned int) MBR_SIGNATURE);
|
|
||||||
} /* if */
|
|
||||||
|
|
||||||
// Find disk size
|
// Find disk size
|
||||||
diskSize = disksize(fd, &err);
|
diskSize = disksize(fd, &err);
|
||||||
|
|
||||||
// Find block size
|
// Find block size
|
||||||
|
if (checkBlockSize) {
|
||||||
if ((blockSize = GetBlockSize(fd)) == -1) {
|
if ((blockSize = GetBlockSize(fd)) == -1) {
|
||||||
blockSize = SECTOR_SIZE;
|
blockSize = SECTOR_SIZE;
|
||||||
printf("Unable to determine sector size; assuming %lu bytes!\n",
|
printf("Unable to determine sector size; assuming %lu bytes!\n",
|
||||||
(unsigned long) SECTOR_SIZE);
|
(unsigned long) SECTOR_SIZE);
|
||||||
} // if
|
} // if
|
||||||
|
} // if (checkBlockSize)
|
||||||
|
|
||||||
// Load logical partition data, if any is found....
|
// Load logical partition data, if any is found....
|
||||||
if (allOK) {
|
if (allOK) {
|
||||||
@@ -242,33 +258,55 @@ int MBRData::WriteMBRData(void) {
|
|||||||
// Save the MBR data to a file. Note that this function writes ONLY the
|
// Save the MBR data to a file. Note that this function writes ONLY the
|
||||||
// MBR data, not the logical partitions (if any are defined).
|
// MBR data, not the logical partitions (if any are defined).
|
||||||
void MBRData::WriteMBRData(int fd) {
|
void MBRData::WriteMBRData(int fd) {
|
||||||
int i;
|
int i, j;
|
||||||
|
TempMBR tempMBR;
|
||||||
|
|
||||||
// Reverse the byte order, if necessary
|
// Reverse the byte order, if necessary
|
||||||
if (IsLittleEndian() == 0) {
|
if (IsLittleEndian() == 0) {
|
||||||
ReverseBytes((char*) &diskSignature, 4);
|
ReverseBytes(&diskSignature, 4);
|
||||||
ReverseBytes((char*) &nulls, 2);
|
ReverseBytes(&nulls, 2);
|
||||||
ReverseBytes((char*) &MBRSignature, 2);
|
ReverseBytes(&MBRSignature, 2);
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
ReverseBytes((char*) &partitions[i].firstLBA, 4);
|
ReverseBytes(&partitions[i].firstLBA, 4);
|
||||||
ReverseBytes((char*) &partitions[i].lengthLBA, 4);
|
ReverseBytes(&partitions[i].lengthLBA, 4);
|
||||||
} // for
|
} // for
|
||||||
} // if
|
} // 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, &diskSignature, 4);
|
||||||
write(fd, &nulls, 2);
|
write(fd, &nulls, 2);
|
||||||
write(fd, partitions, 64);
|
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) {
|
if (IsLittleEndian() == 0) {
|
||||||
ReverseBytes((char*) &diskSignature, 4);
|
ReverseBytes(&diskSignature, 4);
|
||||||
ReverseBytes((char*) &nulls, 2);
|
ReverseBytes(&nulls, 2);
|
||||||
ReverseBytes((char*) &MBRSignature, 2);
|
ReverseBytes(&MBRSignature, 2);
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
ReverseBytes((char*) &partitions[i].firstLBA, 4);
|
ReverseBytes(&partitions[i].firstLBA, 4);
|
||||||
ReverseBytes((char*) &partitions[i].lengthLBA, 4);
|
ReverseBytes(&partitions[i].lengthLBA, 4);
|
||||||
} // for
|
} // for
|
||||||
}// if
|
}// if
|
||||||
} // MBRData::WriteMBRData(int fd)
|
} // MBRData::WriteMBRData(int fd)
|
||||||
@@ -293,11 +331,11 @@ int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
|
|||||||
(unsigned long) offset);
|
(unsigned long) offset);
|
||||||
partNum = -1;
|
partNum = -1;
|
||||||
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
|
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
|
||||||
ReverseBytes((char*) &ebr.MBRSignature, 2);
|
ReverseBytes(&ebr.MBRSignature, 2);
|
||||||
ReverseBytes((char*) &ebr.partitions[0].firstLBA, 4);
|
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
|
||||||
ReverseBytes((char*) &ebr.partitions[0].lengthLBA, 4);
|
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
|
||||||
ReverseBytes((char*) &ebr.partitions[1].firstLBA, 4);
|
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
|
||||||
ReverseBytes((char*) &ebr.partitions[1].lengthLBA, 4);
|
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
|
||||||
} // if/else/if
|
} // if/else/if
|
||||||
|
|
||||||
if (ebr.MBRSignature != MBR_SIGNATURE) {
|
if (ebr.MBRSignature != MBR_SIGNATURE) {
|
||||||
@@ -356,14 +394,19 @@ void MBRData::DisplayMBRData(void) {
|
|||||||
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
|
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
|
||||||
} // MBRData::DisplayMBRData()
|
} // MBRData::DisplayMBRData()
|
||||||
|
|
||||||
// Create a protective MBR
|
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
|
||||||
void MBRData::MakeProtectiveMBR(void) {
|
void MBRData::MakeProtectiveMBR(int clearBoot) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Initialize variables
|
// Initialize variables
|
||||||
nulls = 0;
|
nulls = 0;
|
||||||
MBRSignature = MBR_SIGNATURE;
|
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
|
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
|
// 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;
|
return thePart;
|
||||||
} // GetPartition()
|
} // 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) {
|
void MBRData::ShowState(void) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case invalid:
|
case invalid:
|
||||||
printf("invalid");
|
printf(" MBR: not present\n");
|
||||||
break;
|
break;
|
||||||
case gpt:
|
case gpt:
|
||||||
printf("gpt");
|
printf(" MBR: protective\n");
|
||||||
break;
|
break;
|
||||||
case hybrid:
|
case hybrid:
|
||||||
printf("hybrid");
|
printf(" MBR: hybrid\n");
|
||||||
break;
|
break;
|
||||||
case mbr:
|
case mbr:
|
||||||
printf("mbr");
|
printf(" MBR: MBR only\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("unknown -- bug!");
|
printf("\a MBR: unknown -- bug!\n");
|
||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
} // MBRData::ShowState()
|
} // MBRData::ShowState()
|
||||||
@@ -602,3 +646,36 @@ uint32_t MBRData::GetLength(int i) {
|
|||||||
retval = UINT32_C(0);
|
retval = UINT32_C(0);
|
||||||
return retval;
|
return retval;
|
||||||
} // MBRData::GetLength()
|
} // 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
21
mbr.h
@@ -1,8 +1,12 @@
|
|||||||
/* mbr.h -- MBR data structure definitions, types, and functions */
|
/* 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 <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include "gptpart.h"
|
||||||
|
|
||||||
#ifndef __MBRSTRUCTS
|
#ifndef __MBRSTRUCTS
|
||||||
#define __MBRSTRUCTS
|
#define __MBRSTRUCTS
|
||||||
@@ -32,6 +36,17 @@ struct MBRRecord {
|
|||||||
uint32_t lengthLBA;
|
uint32_t lengthLBA;
|
||||||
}; // struct MBRRecord
|
}; // 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
|
// Extended Boot Record (EBR) data, used to hold one logical partition's
|
||||||
// data within an extended partition. Includes pointer to next record for
|
// data within an extended partition. Includes pointer to next record for
|
||||||
// in-memory linked-list access. This is similar to MBRData, but with a
|
// in-memory linked-list access. This is similar to MBRData, but with a
|
||||||
@@ -75,7 +90,7 @@ public:
|
|||||||
void EmptyMBR(int clearBootloader = 1);
|
void EmptyMBR(int clearBootloader = 1);
|
||||||
void SetDiskSize(uint64_t ds) {diskSize = ds;}
|
void SetDiskSize(uint64_t ds) {diskSize = ds;}
|
||||||
int ReadMBRData(char* deviceFilename);
|
int ReadMBRData(char* deviceFilename);
|
||||||
void ReadMBRData(int fd);
|
void ReadMBRData(int fd, int checkBlockSize = 1);
|
||||||
int WriteMBRData(void);
|
int WriteMBRData(void);
|
||||||
void WriteMBRData(int fd);
|
void WriteMBRData(int fd);
|
||||||
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
||||||
@@ -83,8 +98,9 @@ public:
|
|||||||
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
||||||
int partNum);
|
int partNum);
|
||||||
void DisplayMBRData(void);
|
void DisplayMBRData(void);
|
||||||
void MakeProtectiveMBR(void);
|
void MakeProtectiveMBR(int clearBoot = 0);
|
||||||
MBRValidity GetValidity(void) {return state;}
|
MBRValidity GetValidity(void) {return state;}
|
||||||
|
void ShowValidity(void);
|
||||||
void ShowState(void);
|
void ShowState(void);
|
||||||
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
|
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
|
||||||
int bootable = 0);
|
int bootable = 0);
|
||||||
@@ -99,6 +115,7 @@ public:
|
|||||||
uint8_t GetType(int i);
|
uint8_t GetType(int i);
|
||||||
uint32_t GetFirstSector(int i);
|
uint32_t GetFirstSector(int i);
|
||||||
uint32_t GetLength(int i);
|
uint32_t GetLength(int i);
|
||||||
|
GPTPart AsGPT(int i);
|
||||||
}; // struct MBRData
|
}; // struct MBRData
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
// Class to manage partition type codes -- a slight variant on MBR type
|
// Class to manage partition type codes -- a slight variant on MBR type
|
||||||
// codes, GUID type codes, and associated names.
|
// 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_LIMIT_MACROS
|
||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
|
|||||||
@@ -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 <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|||||||
22
support.cc
22
support.cc
@@ -3,6 +3,9 @@
|
|||||||
// Primarily by Rod Smith, February 2009, but with a few functions
|
// Primarily by Rod Smith, February 2009, but with a few functions
|
||||||
// copied from other sources (see attributions below).
|
// 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_LIMIT_MACROS
|
||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
|
|
||||||
@@ -176,8 +179,12 @@ int GetBlockSize(int fd) {
|
|||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
err = ioctl(fd, DKIOCGETBLOCKSIZE, &result);
|
err = ioctl(fd, DKIOCGETBLOCKSIZE, &result);
|
||||||
|
#else
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
err = ioctl(fd, DIOCGSECTORSIZE, &result);
|
||||||
#else
|
#else
|
||||||
err = ioctl(fd, BLKSSZGET, &result);
|
err = ioctl(fd, BLKSSZGET, &result);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (result != 512) {
|
if (result != 512) {
|
||||||
@@ -319,15 +326,17 @@ int IsLittleEndian(void) {
|
|||||||
} // IsLittleEndian()
|
} // IsLittleEndian()
|
||||||
|
|
||||||
// Reverse the byte order of theValue; numBytes is number of bytes
|
// 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;
|
char* tempValue;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
origValue = (char*) theValue;
|
||||||
tempValue = (char*) malloc(numBytes);
|
tempValue = (char*) malloc(numBytes);
|
||||||
for (i = 0; i < numBytes; i++)
|
for (i = 0; i < numBytes; i++)
|
||||||
tempValue[i] = theValue[i];
|
tempValue[i] = origValue[i];
|
||||||
for (i = 0; i < numBytes; i++)
|
for (i = 0; i < numBytes; i++)
|
||||||
theValue[i] = tempValue[numBytes - i - 1];
|
origValue[i] = tempValue[numBytes - i - 1];
|
||||||
free(tempValue);
|
free(tempValue);
|
||||||
} // ReverseBytes()
|
} // ReverseBytes()
|
||||||
|
|
||||||
@@ -345,6 +354,7 @@ uint64_t PowerOf2(int value) {
|
|||||||
return retval;
|
return retval;
|
||||||
} // PowerOf2()
|
} // PowerOf2()
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************************
|
/**************************************************************************************
|
||||||
* *
|
* *
|
||||||
* Below functions are lifted from various sources, as documented in comments before *
|
* 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....
|
// 32/64-bit issues on MacOS....
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, §ors);
|
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, §ors);
|
||||||
|
#else
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
*err = ioctl(fd, DIOCGMEDIASIZE, &sz);
|
||||||
|
b = GetBlockSize(fd);
|
||||||
|
sectors = sz / b;
|
||||||
#else
|
#else
|
||||||
*err = ioctl(fd, BLKGETSIZE, &sz);
|
*err = ioctl(fd, BLKGETSIZE, &sz);
|
||||||
if (*err) {
|
if (*err) {
|
||||||
@@ -378,6 +393,7 @@ uint64_t disksize(int fd, int *err) {
|
|||||||
sectors = sz;
|
sectors = sz;
|
||||||
else
|
else
|
||||||
sectors = (b >> 9);
|
sectors = (b >> 9);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return sectors;
|
return sectors;
|
||||||
}
|
}
|
||||||
|
|||||||
24
support.h
24
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 <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#if defined (__FreeBSD__) || defined (__APPLE__)
|
||||||
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
|
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
|
||||||
// This used to use __DARWIN_UNIX03 rather than __APPLE__, but __APPLE__
|
// This used to use __DARWIN_UNIX03 rather than __APPLE__, but __APPLE__
|
||||||
// is more general. If the code fails to work on older versions of OS X/
|
// is more general. If the code fails to work on older versions of OS X/
|
||||||
@@ -23,6 +26,23 @@
|
|||||||
// Set this as a default
|
// Set this as a default
|
||||||
#define SECTOR_SIZE UINT32_C(512)
|
#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;
|
using namespace std;
|
||||||
|
|
||||||
// a GUID
|
// a GUID
|
||||||
@@ -39,7 +59,7 @@ int GetBlockSize(int fd);
|
|||||||
char* GUIDToStr(struct GUIDData theGUID, char* theString);
|
char* GUIDToStr(struct GUIDData theGUID, char* theString);
|
||||||
GUIDData GetGUID(void);
|
GUIDData GetGUID(void);
|
||||||
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
|
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 PowerOf2(int value);
|
||||||
|
|
||||||
uint64_t disksize(int fd, int* err);
|
uint64_t disksize(int fd, int* err);
|
||||||
|
|||||||
Reference in New Issue
Block a user