Updates for version 0.4.2

New feature: Ability to edit disk images.
Several small bug fixes and feature enhancements (see CHANGELOG).
This commit is contained in:
srs5694
2009-09-14 00:29:34 -04:00
parent e4ac11ebee
commit e35eb1beb6
14 changed files with 211 additions and 98 deletions

View File

@@ -1,3 +1,30 @@
0.4.2:
------
- Code cleanup.
- Fixed very small formatting bug in display of hex code when a match isn't
found when converting from an MBR/gdisk hex code to a GUID type code.
- Added the ability to work on disk image files (raw files for virtual
machines, backup images, etc.). The program assumes that all such disk
image files have 512-byte sectors.
- Added verification prompt to 'o' main-menu option to avoid accidental
erasures of all partitions.
- The "destroy GPT data structures" option ('z' on the experts' menu) now
also destroys all EFI GPT (0xEE) partitions in the MBR.
- Added an extra warning to the "destroy GPT data structures" option if an APM
or BSD disklabel was detected on the disk.
- Added a buffer flush after destroying GPT data structures, to get the OS
to read the new (empty or MBR-only) partition table.
- Fixed bug that allowed entry of nonexistent partition numbers when creating
a hybrid MBR.
0.4.1:
------

View File

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

View File

@@ -4,7 +4,7 @@
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include "support.h"
#ifndef __GPT_ATTRIBUTES

1
bsd.cc
View File

@@ -64,7 +64,6 @@ int BSDData::ReadBSDData(char* device, uint64_t startSector, uint64_t endSector)
// file, starting with the specified sector number.
void BSDData::ReadBSDData(int fd, uint64_t startSector, uint64_t endSector) {
uint8_t buffer[2048]; // I/O buffer
uint64_t startByte;
int i, err, foundSig = 0, bigEnd = 0;
int relative = 0; // assume absolute partition sector numbering
uint32_t realSig;

View File

@@ -1,6 +1,6 @@
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
.TH GDISK 8 "August 2009" "0.4.1" "GPT fdisk Manual"
.TH GDISK 8 "August 2009" "0.4.2" "GPT fdisk Manual"
.SH NAME
gdisk \- GPT partition table manipulator for Linux and Unix
.SH SYNOPSIS
@@ -425,7 +425,7 @@ menu provides unusually dangerous or obscure options. These are:
Set attributes. GPT provides a 64-bit attributes field that can be used to
set partition features.
.B gdisk
supports four attributes:
supports four attributes:
.IR "system partition",
.IR "read-only",
.IR "hidden",
@@ -548,7 +548,7 @@ the main menu.
.TP
.B z
Destroy the GPT data structures and exit. Use this option if you want to
repartition a GPT disk using
repartition a GPT disk using
.B "fdisk"
or some other GPT-unaware program.
You'll be given the choice of preserving the existing MBR, in case it's a
@@ -562,7 +562,7 @@ entering data. When only one option is possible,
usually bypasses the prompt entirely.
.SH BUGS
As of August of 2009 (version 0.4.1),
As of September 2009 (version 0.4.2),
.B gdisk
should be considered beta software. Known bugs and limitations include:

View File

@@ -27,7 +27,7 @@ int main(int argc, char* argv[]) {
int doMore = 1;
char* device = NULL;
printf("GPT fdisk (gdisk) version 0.4.1\n\n");
printf("GPT fdisk (gdisk) version 0.4.2\n\n");
if (argc == 2) { // basic usage
if (SizesOK()) {
@@ -90,9 +90,12 @@ int DoCommand(char* filename, struct GPTData* theGPT) {
theGPT->CreatePartition();
break;
case 'o': case 'O':
theGPT->ClearGPTData();
theGPT->MakeProtectiveMBR();
// theGPT->BlankPartitions();
printf("This option deletes all partitions and creates a new "
"protective MBR.\nProceed? ");
if (GetYN() == 'Y') {
theGPT->ClearGPTData();
theGPT->MakeProtectiveMBR();
} // if
break;
case 'p': case 'P':
theGPT->DisplayGPTData();

68
gpt.cc
View File

@@ -83,7 +83,7 @@ GPTData::~GPTData(void) {
// do *NOT* recover from these problems. Returns the total number of
// problems identified.
int GPTData::Verify(void) {
int problems = 0, numSegments, i, j;
int problems = 0, numSegments;
uint64_t totalFree, largestSegment;
char tempStr[255], siTotal[255], siLargest[255];
@@ -282,7 +282,7 @@ int GPTData::CheckHeaderValidity(void) {
} // if/else/if
// If MBR bad, check for an Apple disk signature
if ((protectiveMBR.GetValidity() == invalid) &&
if ((protectiveMBR.GetValidity() == invalid) &&
(((mainHeader.signature << 32) == APM_SIGNATURE1) ||
(mainHeader.signature << 32) == APM_SIGNATURE2)) {
apmFound = 1; // Will display warning message later
@@ -317,7 +317,7 @@ int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
// byte order on big-endian systems) if any changes have been made.
void GPTData::RecomputeCRCs(void) {
uint32_t crc;
uint32_t trueNumParts, crcTemp;
uint32_t trueNumParts;
int littleEndian = 1;
// Initialize CRC functions...
@@ -703,7 +703,7 @@ void GPTData::LoadSecondTableAsMain(void) {
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
// write, 0 if there was a problem.
int GPTData::SaveGPTData(void) {
int allOK = 1, i, j;
int allOK = 1, i;
char answer, line[256];
int fd;
uint64_t secondTable;
@@ -806,27 +806,7 @@ int GPTData::SaveGPTData(void) {
// re-read the partition table
if (allOK) {
sync();
#ifdef __APPLE__
printf("Warning: The kernel may continue to use old or deleted partitions.\n"
"You should reboot or remove the drive.\n");
/* don't know if this helps
* it definitely will get things on disk though:
* http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
#else
#ifdef __FreeBSD__
sleep(2);
i = ioctl(fd, DIOCGFLUSH);
printf("Warning: The kernel may still provide disk access using old partition IDs.\n");
#else
sleep(2);
i = ioctl(fd, BLKRRPART);
if (i)
printf("Warning: The kernel is still using the old partition table.\n"
"The new table will be used at the next reboot.\n");
#endif
#endif
DiskSync(fd);
} // if
if (allOK) { // writes completed OK
@@ -1035,7 +1015,7 @@ void GPTData::ShowGPTState(void) {
// Display the basic GPT data
void GPTData::DisplayGPTData(void) {
int i, j;
int i;
char sizeInSI[255]; // String to hold size of disk in SI units
char tempStr[255];
uint64_t temp, totalFree;
@@ -1233,13 +1213,17 @@ void GPTData::SetAttributes(uint32_t partNum) {
// This function destroys the on-disk GPT structures. Returns 1 if the
// user confirms destruction, 0 if the user aborts.
int GPTData::DestroyGPT(void) {
int fd, i, doMore;
int fd, i;
char blankSector[512], goOn;
for (i = 0; i < 512; i++) {
blankSector[i] = '\0';
} // for
if ((apmFound) || (bsdFound)) {
printf("WARNING: APM or BSD disklabel structures detected! This operation could\n"
"damage any APM or BSD partitions on this disk!\n");
} // if APM or BSD
printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
goOn = GetYN();
if (goOn == 'Y') {
@@ -1265,7 +1249,16 @@ int GPTData::DestroyGPT(void) {
if (GetYN() == 'Y') {
lseek64(fd, 0, SEEK_SET);
write(fd, blankSector, 512); // blank it out
} // if blank MBR
} else { // write current protective MBR, in case it's hybrid....
// find and delete 0xEE partitions in MBR
for (i = 0; i < 4; i++) {
if (protectiveMBR.GetType(i) == (uint8_t) 0xEE) {
protectiveMBR.DeletePartition(i);
} // if
} // for
protectiveMBR.WriteMBRData(fd);
} // if/else
DiskSync(fd);
close(fd);
printf("GPT data structures destroyed! You may now partition the disk using fdisk or\n"
"other utilities. Program will now terminate.\n");
@@ -1376,7 +1369,6 @@ int GPTData::XFormPartitions(void) {
int i, numToConvert;
uint8_t origType;
struct newGUID;
char name[NAME_SIZE];
// Clear out old data & prepare basics....
ClearGPTData();
@@ -1391,7 +1383,7 @@ int GPTData::XFormPartitions(void) {
origType = protectiveMBR.GetType(i);
// don't waste CPU time trying to convert extended, hybrid protective, or
// null (non-existent) partitions
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
(origType != 0x00) && (origType != 0xEE))
partitions[i] = protectiveMBR.AsGPT(i);
} // for
@@ -1509,7 +1501,8 @@ void GPTData::MakeHybrid(void) {
j = partNums[i] - 1;
printf("\nCreating entry for partition #%d\n", j + 1);
if ((j >= 0) && (j < mainHeader.numParts)) {
if (partitions[j].GetLastLBA() < UINT32_MAX) {
if ((partitions[j].GetLastLBA() < UINT32_MAX) &&
(partitions[j].GetLastLBA() > UINT64_C(0))) {
do {
printf("Enter an MBR hex code (default %02X): ",
typeHelper.GUIDToID(partitions[j].GetType()) / 256);
@@ -1529,7 +1522,8 @@ void GPTData::MakeHybrid(void) {
(uint32_t) length, typeCode, bootable);
protectiveMBR.SetHybrid();
} 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 or does not exist;\n"
"omitting it.\n",
j + 1);
} // if/else
} else {
@@ -1683,8 +1677,12 @@ void GPTData::SortGPT(void) {
// Set up data structures for entirely new set of partitions on the
// specified device. Returns 1 if OK, 0 if there were problems.
// Note that this function does NOT clear the protectiveMBR data
// structure, since it may hold the original MBR partitions if the
// program was launched on an MBR disk, and those may need to be
// converted to GPT format.
int GPTData::ClearGPTData(void) {
int goOn, i;
int goOn = 1, i;
// Set up the partition table....
free(partitions);
@@ -1835,7 +1833,7 @@ uint64_t GPTData::FindFirstAvailable(uint64_t start) {
// Finds the first available sector in the largest block of unallocated
// space on the disk. Returns 0 if there are no available blocks left
uint64_t GPTData::FindFirstInLargest(void) {
uint64_t start, firstBlock, lastBlock, segmentSize, selectedSize = 0, selectedSegment;
uint64_t start, firstBlock, lastBlock, segmentSize, selectedSize = 0, selectedSegment = 0;
start = 0;
do {
@@ -1937,7 +1935,7 @@ int GPTData::IsFree(uint64_t sector) {
isFree = 0;
} // if
} // for
if ((sector < mainHeader.firstUsableLBA) ||
if ((sector < mainHeader.firstUsableLBA) ||
(sector > mainHeader.lastUsableLBA)) {
isFree = 0;
} // if

View File

@@ -68,6 +68,7 @@ GPTPart & GPTPart::operator=(const GPTPart & orig) {
attributes = orig.attributes;
for (i = 0; i < NAME_SIZE; i++)
name[i] = orig.name[i];
return *this;
} // assignment operator
// Sets the unique GUID to a value of 0 or a random value,

43
mbr.cc
View File

@@ -179,11 +179,12 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
// Find block size
if (checkBlockSize) {
if ((blockSize = GetBlockSize(fd)) == -1) {
blockSize = SECTOR_SIZE;
printf("Unable to determine sector size; assuming %lu bytes!\n",
(unsigned long) SECTOR_SIZE);
} // if
blockSize = GetBlockSize(fd);
// if ((blockSize = GetBlockSize(fd)) == -1) {
// blockSize = SECTOR_SIZE;
// printf("Unable to determine sector size; assuming %lu bytes!\n",
// (unsigned long) SECTOR_SIZE);
// } // if
} // if (checkBlockSize)
// Load logical partition data, if any is found....
@@ -291,6 +292,7 @@ void MBRData::WriteMBRData(int fd) {
} // for i...
// Now write that data structure...
lseek64(fd, 0, SEEK_SET);
write(fd, &tempMBR, 512);
/* write(fd, code, 440);
@@ -298,7 +300,7 @@ void MBRData::WriteMBRData(int fd) {
write(fd, &nulls, 2);
write(fd, partitions, 64);
write(fd, &MBRSignature, 2); */
// Reverse the byte order back, if necessary
if (IsLittleEndian() == 0) {
ReverseBytes(&diskSignature, 4);
@@ -496,6 +498,20 @@ int MBRData::MakeBiggestPart(int i, int type) {
return found;
} // MBRData::MakeBiggestPart(int i)
// Delete partition #i
void MBRData::DeletePartition(int i) {
int j;
partitions[i].firstLBA = UINT32_C(0);
partitions[i].lengthLBA = UINT32_C(0);
partitions[i].status = UINT8_C(0);
partitions[i].partitionType = UINT8_C(0);
for (j = 0; j < 3; j++) {
partitions[i].firstSector[j] = UINT8_C(0);
partitions[i].lastSector[j] = UINT8_C(0);
} // for j (CHS data blanking)
} // MBRData::DeletePartition()
// Delete a partition if one exists at the specified location.
// Returns 1 if a partition was deleted, 0 otherwise....
// Used to help keep GPT & hybrid MBR partitions in sync....
@@ -509,14 +525,7 @@ int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
for (i = 0; i < 4; i++) {
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
(partitions[i].partitionType != 0xEE)) {
partitions[i].firstLBA = UINT32_C(0);
partitions[i].lengthLBA = UINT32_C(0);
partitions[i].status = UINT8_C(0);
partitions[i].partitionType = UINT8_C(0);
for (j = 0; j < 3; j++) {
partitions[i].firstSector[j] = UINT8_C(0);
partitions[i].lastSector[j] = UINT8_C(0);
} // for j (CHS data blanking)
DeletePartition(i);
OptimizeEESize();
deleted = 1;
} // if (match found)
@@ -594,7 +603,7 @@ void MBRData::ShowState(void) {
// setup to begin with....
void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
int bootable) {
partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
partitions[num].firstSector[0] = UINT8_C(0);
partitions[num].firstSector[1] = UINT8_C(0);
@@ -657,7 +666,7 @@ uint32_t MBRData::FindLastInFree(uint32_t start) {
// Finds the first free sector on the disk from start backward.
uint32_t MBRData::FindFirstInFree(uint32_t start) {
uint32_t nearestStart, bestLastLBA, thisLastLBA;
uint32_t bestLastLBA, thisLastLBA;
int i;
bestLastLBA = 1;
@@ -752,7 +761,7 @@ GPTPart MBRData::AsGPT(int i) {
// 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) &&
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
(origType != 0x00) && (origType != 0xEE)) {
firstSector = (uint64_t) origPart->firstLBA;
newPart.SetFirstLBA(firstSector);

1
mbr.h
View File

@@ -105,6 +105,7 @@ public:
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
int bootable = 0);
int MakeBiggestPart(int i, int type); // Make partition filling most space
void DeletePartition(int i);
int DeleteByLocation(uint64_t start64, uint64_t length64);
void OptimizeEESize(void);
void SetHybrid(void) {state = hybrid;} // Set hybrid flag

View File

@@ -293,6 +293,14 @@ struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
int found = 0;
struct GUIDData theGUID;
// Start by assigning a default GUID for the return value. Done
// "raw" to avoid the necessity for a recursive call and the
// remote possibility of an infinite recursive loop that this
// approach would present....
theGUID.data1 = UINT64_C(0x4433B9E5EBD0A0A2);
theGUID.data2 = UINT64_C(0xC79926B7B668C087);
// Now search the type list for a match to the ID....
while ((theItem != NULL) && (!found)) {
if (theItem->MBRType == ID) { // found it!
theGUID = theItem->GUIDType;
@@ -302,8 +310,7 @@ struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
} // if/else
} // while
if (!found) {
theGUID = IDToGUID(0x0700); // assign a default type code
printf("Exact type match not found for type code %lx; assigning type code for\n'Linux/Windows data'\n",
printf("Exact type match not found for type code %04X; assigning type code for\n'Linux/Windows data'\n",
ID);
} // if (!found)
return theGUID;
@@ -317,7 +324,7 @@ struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
uint16_t PartTypes::GUIDToID(struct GUIDData typeCode) {
AType* theItem = allTypes;
int found = 0;
uint16_t theID;
uint16_t theID = 0xFFFF;
while ((theItem != NULL) && (!found)) {
if ((theItem->GUIDType.data1 == typeCode.data1) &&

View File

@@ -4,7 +4,7 @@
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include "support.h"
#ifndef __PARTITION_TYPES

View File

@@ -15,6 +15,7 @@
#include <stdint.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "support.h"
#include <sys/types.h>
@@ -184,8 +185,9 @@ char* BytesToSI(uint64_t size, char theValue[]) {
return theValue;
} // BlocksToSI()
// Returns block size of device pointed to by fd file descriptor, or -1
// if there's a problem
// Returns block size of device pointed to by fd file descriptor. If the ioctl
// returns an error condition, print a warning but return a value of SECTOR_SIZE
// (512)..
int GetBlockSize(int fd) {
int err, result;
@@ -199,13 +201,21 @@ int GetBlockSize(int fd) {
#endif
#endif
if (err == -1) {
result = SECTOR_SIZE;
// ENOTTY = inappropriate ioctl; probably being called on a disk image
// file, so don't display the warning message....
if (errno != ENOTTY) {
printf("\aError %d when determining sector size! Setting sector size to %d\n",
errno, SECTOR_SIZE);
} // if
} // if
if (result != 512) {
printf("\aWARNING! Sector size is not 512 bytes! This program is likely to ");
printf("misbehave!\nProceed at your own risk!\n\n");
} // if
if (err == -1)
result = -1;
return (result);
} // GetBlockSize()
@@ -380,7 +390,37 @@ int OpenForWrite(char* deviceFilename) {
fd = open(deviceFilename, O_WRONLY|O_SHLOCK);
} // if
#endif
} // MyOpen()
return fd;
} // OpenForWrite()
// Resync disk caches so the OS uses the new partition table. This code varies
// a lot from one OS to another.
void DiskSync(int fd) {
int i;
sync();
#ifdef __APPLE__
printf("Warning: The kernel may continue to use old or deleted partitions.\n"
"You should reboot or remove the drive.\n");
/* don't know if this helps
* it definitely will get things on disk though:
* http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */
i = ioctl(fd, DKIOCSYNCHRONIZECACHE);
#else
#ifdef __FreeBSD__
sleep(2);
i = ioctl(fd, DIOCGFLUSH);
printf("Warning: The kernel may continue to use old or deleted partitions.\n"
"You should reboot or remove the drive.\n");
#else
sleep(2);
i = ioctl(fd, BLKRRPART);
if (i)
printf("Warning: The kernel is still using the old partition table.\n"
"The new table will be used at the next reboot.\n");
#endif
#endif
} // DiskSync()
/**************************************************************************************
* *
@@ -392,35 +432,62 @@ int OpenForWrite(char* deviceFilename) {
// The disksize function is taken from the Linux fdisk code and modified
// to work around a problem returning a uint64_t value on Mac OS.
uint64_t disksize(int fd, int *err) {
long sz; // Do not delete; needed for Linux
long long b; // Do not delete; needed for Linux
uint64_t sectors;
long sz; // Do not delete; needed for Linux
long long b; // Do not delete; needed for Linux
uint64_t sectors = 0, bytes = 0; // size in sectors & bytes
struct stat st;
// Note to self: I recall testing a simplified version of
// this code, similar to what's in the __APPLE__ block,
// on Linux, but I had some problems. IIRC, it ran OK on 32-bit
// systems but not on 64-bit. Keep this in mind in case of
// 32/64-bit issues on MacOS....
// Note to self: I recall testing a simplified version of
// this code, similar to what's in the __APPLE__ block,
// on Linux, but I had some problems. IIRC, it ran OK on 32-bit
// systems but not on 64-bit. Keep this in mind in case of
// 32/64-bit issues on MacOS....
#ifdef __APPLE__
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, &sectors);
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, &sectors);
#else
#ifdef __FreeBSD__
*err = ioctl(fd, DIOCGMEDIASIZE, &sz);
b = GetBlockSize(fd);
sectors = sz / b;
*err = ioctl(fd, DIOCGMEDIASIZE, &sz);
b = GetBlockSize(fd);
sectors = sz / b;
#else
*err = ioctl(fd, BLKGETSIZE, &sz);
if (*err) {
sz = 0;
if (errno != EFBIG)
return sz;
}
*err = ioctl(fd, BLKGETSIZE64, &b);
if (*err || b == 0 || b == sz)
sectors = sz;
else
sectors = (b >> 9);
*err = ioctl(fd, BLKGETSIZE, &sz);
if (*err) {
sectors = sz = 0;
} // if
if ((errno == EFBIG) || (!*err)) {
*err = ioctl(fd, BLKGETSIZE64, &b);
if (*err || b == 0 || b == sz)
sectors = sz;
else
sectors = (b >> 9);
} // if
// if (*err) {
// sz = 0;
// if (errno != EFBIG)
// return sz;
// }
// *err = ioctl(fd, BLKGETSIZE64, &b);
// if (*err || b == 0 || b == sz)
// sectors = sz;
// else
// sectors = (b >> 9);
#endif
#endif
return sectors;
// The above methods have failed (or it's a bum filename reference),
// so let's assume it's a regular file (a QEMU image, dd backup, or
// what have you) and see what stat() gives us....
if (sectors == 0) {
if (fstat(fd, &st) == 0) {
bytes = (uint64_t) st.st_size;
if ((bytes % UINT64_C(512)) != 0)
fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
" Misbehavior is likely!\n\a");
sectors = bytes / UINT64_C(512);
} // if
} // if
// printf("In disksize(), sectors is %lld.\n", sectors);
return sectors;
}

View File

@@ -18,7 +18,7 @@
#include <linux/fs.h>
#endif
#include <string>
#include <string.h>
#ifndef __GPTSUPPORT
#define __GPTSUPPORT
@@ -62,6 +62,7 @@ int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-en
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
uint64_t PowerOf2(int value);
int OpenForWrite(char* deviceFilename);
void DiskSync(int fd); // resync disk caches to use new partitions
uint64_t disksize(int fd, int* err);