summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile15
-rw-r--r--Makefile.freebsd12
-rw-r--r--Makefile.mac12
-rw-r--r--NEWS33
-rw-r--r--basicmbr.cc4
-rw-r--r--current.spec23
-rw-r--r--diskio-unix.cc13
-rw-r--r--diskio-windows.cc6
-rw-r--r--diskio.h2
-rw-r--r--fixparts.85
-rw-r--r--gdisk.829
-rw-r--r--gdisk.cc391
-rw-r--r--gpt.cc31
-rw-r--r--gpttext.cc378
-rw-r--r--gpttext.h12
-rw-r--r--mbrpart.cc24
-rw-r--r--mbrpart.h4
-rw-r--r--parttypes.cc4
-rw-r--r--sgdisk.842
-rw-r--r--sgdisk.cc506
-rw-r--r--support.cc18
-rw-r--r--support.h5
22 files changed, 581 insertions, 988 deletions
diff --git a/Makefile b/Makefile
index 4c3271e..f0157c1 100644
--- a/Makefile
+++ b/Makefile
@@ -11,15 +11,19 @@ MBR_LIB_OBJS=$(MBR_LIBS:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
DEPEND= makedepend $(CXXFLAGS)
-all: gdisk sgdisk fixparts
+all: cgdisk gdisk sgdisk fixparts
gdisk: $(LIB_OBJS) gdisk.o gpttext.o
# $(CXX) $(LIB_OBJS) gdisk.o gpttext.o $(LDFLAGS) -luuid -o gdisk
$(CXX) $(LIB_OBJS) gdisk.o gpttext.o $(LDFLAGS) -licuio -licuuc -luuid -o gdisk
-sgdisk: $(LIB_OBJS) sgdisk.o
-# $(CXX) $(LIB_OBJS) sgdisk.o $(LDFLAGS) -luuid -lpopt -o sgdisk
- $(CXX) $(LIB_OBJS) sgdisk.o $(LDFLAGS) -licuio -licuuc -luuid -lpopt -o sgdisk
+cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o
+# $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -luuid -lncurses -o cgdisk
+ $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -licuio -licuuc -luuid -lncurses -o cgdisk
+
+sgdisk: $(LIB_OBJS) sgdisk.o gptcl.o
+# $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o $(LDFLAGS) -luuid -lpopt -o sgdisk
+ $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o $(LDFLAGS) -licuio -licuuc -luuid -lpopt -o sgdisk
fixparts: $(MBR_LIB_OBJS) fixparts.o
$(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -o fixparts
@@ -28,7 +32,7 @@ lint: #no pre-reqs
lint $(SRCS)
clean: #no pre-reqs
- rm -f core *.o *~ gdisk sgdisk fixparts
+ rm -f core *.o *~ gdisk sgdisk cgdisk fixparts
# what are the source dependencies
depend: $(SRCS)
@@ -38,3 +42,4 @@ $(OBJS):
$(CRITICAL_CXX_FLAGS)
# DO NOT DELETE
+
diff --git a/Makefile.freebsd b/Makefile.freebsd
index b0258f8..d36dc92 100644
--- a/Makefile.freebsd
+++ b/Makefile.freebsd
@@ -11,15 +11,19 @@ MBR_LIB_OBJS=$(MBR_LIBS:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
DEPEND= makedepend $(CXXFLAGS)
-all: gdisk sgdisk fixparts
+all: gdisk cgdisk sgdisk fixparts
gdisk: $(LIB_OBJS) gdisk.o gpttext.o
$(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/usr/local/lib $(LDFLAGS) -licuio -luuid -o gdisk
# $(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/usr/local/lib $(LDFLAGS) -luuid -o gdisk
-sgdisk: $(LIB_OBJS) sgdisk.o
- $(CXX) $(LIB_OBJS) sgdisk.o -L/usr/local/lib $(LDFLAGS) -luuid -licuio -lpopt -o sgdisk
-# $(CXX) $(LIB_OBJS) sgdisk.o -L/usr/local/lib $(LDFLAGS) -luuid -lpopt -o sgdisk
+cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o
+ $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o -L/usr/local/lib $(LDFLAGS) -licuio -luuid -lncurses -o cgdisk
+# $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o -L/usr/local/lib $(LDFLAGS) -luuid -lncurses -o cgdisk
+
+sgdisk: $(LIB_OBJS) sgdisk.o gptcl.o
+ $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o -L/usr/local/lib $(LDFLAGS) -luuid -licuio -lpopt -o sgdisk
+# $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o -L/usr/local/lib $(LDFLAGS) -luuid -lpopt -o sgdisk
fixparts: $(MBR_LIB_OBJS) fixparts.o
$(CXX) $(MBR_LIB_OBJS) fixparts.o -L/usr/local/lib $(LDFLAGS) -o fixparts
diff --git a/Makefile.mac b/Makefile.mac
index 4ab08e1..a9b5315 100644
--- a/Makefile.mac
+++ b/Makefile.mac
@@ -11,15 +11,19 @@ MBR_LIB_OBJS=$(MBR_LIBS:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
DEPEND= makedepend $(CFLAGS)
-all: gdisk sgdisk fixparts
+all: gdisk sgdisk cgdisk fixparts
gdisk: $(LIB_OBJS) gpttext.o gdisk.o
# $(CXX) $(LIB_OBJS) gpttext.o gdisk.o -o gdisk
$(CXX) $(LIB_OBJS) -L/usr/lib -licucore gpttext.o gdisk.o -o gdisk
-sgdisk: $(LIB_OBJS) sgdisk.o
-# $(CXX) $(LIB_OBJS) sgdisk.o -L/sw/lib -lpopt -o sgdisk
- $(CXX) $(LIB_OBJS) sgdisk.o -L/sw/lib -licucore -lpopt -o sgdisk
+cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o
+# $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -lncurses -o sgdisk
+ $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -licucore -lncurses -o cgdisk
+
+sgdisk: $(LIB_OBJS) gptcl.o sgdisk.o
+# $(CXX) $(LIB_OBJS) gptcl.o sgdisk.o -L/sw/lib -lpopt -o sgdisk
+ $(CXX) $(LIB_OBJS) gptcl.o sgdisk.o -L/sw/lib -licucore -lpopt -o sgdisk
fixparts: $(MBR_LIB_OBJS) fixparts.o
$(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -o fixparts
diff --git a/NEWS b/NEWS
index 07dd807..6496a16 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,36 @@
+0.8.0 (9/10/2011):
+------------------
+
+- Added new return option for sgdisk: 8, which means that a replication
+ operation (-R or --replicate) failed. Note that other operations on
+ the same command line might still have succeeded.
+
+- Added gdisk_test.sh shell script, contributed by Guillaume Delacour.
+ This script tests some common gdisk and sgdisk operations to be sure
+ they're working correctly.
+
+- Enable sgdisk's -l (--load-backup) and -o (--clear) options to work
+ even on disks that are damaged. Most other options will still be ignored,
+ though, so if you suspect a disk may be bad and want to use one of these
+ options, you should do so on a line by itself, followed by a separate
+ command to perform other actions (such as adding new partitions).
+
+- Added check for mis-matched primary and backup partition tables.
+ A mismatch is reported as a CRC error.
+
+- Added Apple Core Storage partition type code (hex code AF05, GUID
+ 53746F72-6167-11AA-AA11-00306543ECAC).
+
+- Added cgdisk program to the family. This program is a rough workalike
+ to cfdisk, much as gdisk is a rough workalike to fdisk. See the cgdisk
+ man page or http://www.rodsbooks.com/gdisk/cgdisk-walkthrough.html for
+ details about its operation.
+
+- Fixed bug that caused CHS end point for protective MBR to be set to
+ 0xfeffff rather than the spec-mandated 0xffffff on disks over ~8GB. This
+ is a very minor bug, since not much cares about this, and most other GPT
+ tools get it wrong in the same way, too.
+
0.7.2 (6/26/2011):
------------------
diff --git a/basicmbr.cc b/basicmbr.cc
index 4f193e2..797c4f2 100644
--- a/basicmbr.cc
+++ b/basicmbr.cc
@@ -606,8 +606,12 @@ int BasicMBRData::BlankGPTData(void) {
// the most common value for big disks (255 heads, 63 sectors per
// track, & however many cylinders that computes to).
void BasicMBRData::ReadCHSGeom(void) {
+ int err;
+
numHeads = myDisk->GetNumHeads();
numSecspTrack = myDisk->GetNumSecsPerTrack();
+ diskSize = myDisk->DiskSize(&err);
+ blockSize = myDisk->GetBlockSize();
partitions[0].SetGeometry(numHeads, numSecspTrack, diskSize, blockSize);
} // BasicMBRData::ReadCHSGeom()
diff --git a/current.spec b/current.spec
index 109285c..0296294 100644
--- a/current.spec
+++ b/current.spec
@@ -1,21 +1,20 @@
Summary: GPT partitioning and MBR repair software
Name: gptfdisk
-Version: 0.7.2
+Version: 0.8.0
Release: 1%{?dist}
License: GPLv2
URL: http://www.rodsbooks.com/gdisk
Group: Applications/System
-Source: http://www.rodsbooks.com/gdisk/gptfdisk-0.7.2.tar.gz
+Source: http://www.rodsbooks.com/gdisk/gptfdisk-0.8.0.tar.gz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%description
-Partitioning software for GPT disks and to repair MBR
-disks. The gdisk and sgdisk utilities (in the gdisk
-package) are GPT-enabled partitioning tools; the
-fixparts utility (in the fixparts package) fixes some
-problems with MBR disks that can be created by buggy
-partitioning software.
+Partitioning software for GPT disks and to repair MBR disks. The gdisk,
+cgdisk, and sgdisk utilities (in the gdisk package) are GPT-enabled
+partitioning tools; the fixparts utility (in the fixparts package) fixes
+some problems with MBR disks that can be created by buggy partitioning
+software.
%package -n gdisk
@@ -41,9 +40,11 @@ rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/sbin
install -Dp -m0755 gdisk $RPM_BUILD_ROOT/usr/sbin
install -Dp -m0755 sgdisk $RPM_BUILD_ROOT/usr/sbin
+install -Dp -m0755 cgdisk $RPM_BUILD_ROOT/usr/sbin
install -Dp -m0755 fixparts $RPM_BUILD_ROOT/usr/sbin
install -Dp -m0644 gdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/gdisk.8
install -Dp -m0644 sgdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/sgdisk.8
+install -Dp -m0644 cgdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/cgdisk.8
install -Dp -m0644 fixparts.8 $RPM_BUILD_ROOT/%{_mandir}/man8/fixparts.8
%clean
@@ -54,8 +55,10 @@ rm -rf $RPM_BUILD_ROOT
%doc NEWS COPYING README
/usr/sbin/gdisk
/usr/sbin/sgdisk
+/usr/sbin/cgdisk
%doc %{_mandir}/man8/gdisk.8*
%doc %{_mandir}/man8/sgdisk.8*
+%doc %{_mandir}/man8/cgdisk.8*
%package -n fixparts
@@ -77,5 +80,5 @@ provides a few additional partition manipulation features.
%changelog
-* Sun Jun 26 2011 R Smith <rodsmith@rodsbooks.com> - 0.7.2
-- Created spec file for 0.7.2 release
+* Sat Sep 10 2011 R Smith <rodsmith@rodsbooks.com> - 0.8.0
+- Created spec file for 0.8.0 release
diff --git a/diskio-unix.cc b/diskio-unix.cc
index 03fc3c8..3735b9f 100644
--- a/diskio-unix.cc
+++ b/diskio-unix.cc
@@ -203,8 +203,11 @@ uint32_t DiskIO::GetNumSecsPerTrack(void) {
// Resync disk caches so the OS uses the new partition table. This code varies
// a lot from one OS to another.
-void DiskIO::DiskSync(void) {
- int i, platformFound = 0;
+// Returns 1 on success, 0 if the kernel continues to use the old partition table.
+// (Note that for most OSes, the default of 0 is returned because I've not yet
+// looked into how to test for success in the underlying system calls...)
+int DiskIO::DiskSync(void) {
+ int i, retval = 0, platformFound = 0;
// If disk isn't open, try to open it....
if (!isOpen) {
@@ -233,9 +236,12 @@ void DiskIO::DiskSync(void) {
sleep(1); // Theoretically unnecessary, but ioctl() fails sometimes if omitted....
fsync(fd);
i = ioctl(fd, BLKRRPART);
- if (i)
+ if (i) {
cout << "Warning: The kernel is still using the old partition table.\n"
<< "The new table will be used at the next reboot.\n";
+ } else {
+ retval = 1;
+ } // if/else
platformFound++;
#endif
if (platformFound == 0)
@@ -243,6 +249,7 @@ void DiskIO::DiskSync(void) {
if (platformFound > 1)
cerr << "\nWarning: We seem to be running on multiple platforms!\n";
} // if (isOpen)
+ return retval;
} // DiskIO::DiskSync()
// Seek to the specified sector. Returns 1 on success, 0 on failure.
diff --git a/diskio-windows.cc b/diskio-windows.cc
index 37e5bb5..af191a8 100644
--- a/diskio-windows.cc
+++ b/diskio-windows.cc
@@ -158,9 +158,11 @@ uint32_t DiskIO::GetNumSecsPerTrack(void) {
// Resync disk caches so the OS uses the new partition table. This code varies
// a lot from one OS to another.
-void DiskIO::DiskSync(void) {
+// Returns 1 on success, 0 if the kernel continues to use the old partition table.
+int DiskIO::DiskSync(void) {
DWORD i;
GET_LENGTH_INFORMATION buf;
+ int retval = 0;
// If disk isn't open, try to open it....
if (!openForWrite) {
@@ -174,12 +176,14 @@ void DiskIO::DiskSync(void) {
} else {
cout << "Disk synchronization succeeded! The computer should now use the new\n"
<< "partition table.\n";
+ retval = 1;
} // if/else
} else {
cout << "Unable to open the disk for synchronization operation! The computer will\n"
<< "continue to use the old partition table until you reboot or remove and\n"
<< "re-insert the disk!\n";
} // if (isOpen)
+ return retval;
} // DiskIO::DiskSync()
// Seek to the specified sector. Returns 1 on success, 0 on failure.
diff --git a/diskio.h b/diskio.h
index 7bb01e6..3102077 100644
--- a/diskio.h
+++ b/diskio.h
@@ -65,7 +65,7 @@ class DiskIO {
int Seek(uint64_t sector);
int Read(void* buffer, int numBytes);
int Write(void* buffer, int numBytes);
- void DiskSync(void); // resync disk caches to use new partitions
+ int DiskSync(void); // resync disk caches to use new partitions
int GetBlockSize(void);
uint32_t GetNumHeads(void);
uint32_t GetNumSecsPerTrack(void);
diff --git a/fixparts.8 b/fixparts.8
index e8bd74f..ffa7963 100644
--- a/fixparts.8
+++ b/fixparts.8
@@ -1,6 +1,6 @@
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
-.TH "FIXPARTS" "8" "0.7.2" "Roderick W. Smith" "FixParts Manual"
+.TH "FIXPARTS" "8" "0.8.0" "Roderick W. Smith" "FixParts Manual"
.SH "NAME"
fixparts \- MBR partition table repair utility
.SH "SYNOPSIS"
@@ -202,7 +202,7 @@ see a summary of available options.
.PP
.SH "BUGS"
-As of June 2011 (version 0.7.2), \fBfixparts\fR
+As of September 2011 (version 0.8.0), \fBfixparts\fR
should be considered beta software. Known bugs and limitations include:
.TP
@@ -266,6 +266,7 @@ Contributors:
.SH "SEE ALSO"
\fBcfdisk (8)\fR,
+\fBcgdisk (8)\fR,
\fBfdisk (8)\fR,
\fBmkfs (8)\fR,
\fBparted (8)\fR,
diff --git a/gdisk.8 b/gdisk.8
index 850b459..4339e8c 100644
--- a/gdisk.8
+++ b/gdisk.8
@@ -1,6 +1,6 @@
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
-.TH "GDISK" "8" "0.7.2" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "GDISK" "8" "0.8.0" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS"
@@ -93,7 +93,7 @@ and in whatever sizes are desired.
.B *
Boot disks for EFI\-based systems require an \fIEFI System
Partition\fR (\fBgdisk\fR internal code 0xEF00) formatted as FAT\-32.
-The recommended size of this partition is between 100 and 200 MiB.
+The recommended size of this partition is between 100 and 300 MiB.
Boot\-related files are stored here. (Note that GNU Parted identifies
such partitions as having the "boot flag" set.)
@@ -467,15 +467,15 @@ option on the main menu.
.TP
.B l
Change the sector alignment value. Disks with more logical sectors per
-physical sectors (such as some Western Digital models introduced in
-December of 2009) and some RAID configurations can suffer performance
-problems if partitions are not aligned properly for their internal data
-structures. On new disks, GPT fdisk attempts to align partitions on
-2048\-sector (1MiB) boundaries by default, which optimizes performance for
-both of these disk types. On pre\-partitioned disks, GPT fdisk attempts to
-identify the alignment value used on that disk, but will set 8-sector
-alignment on disks larger than 300 GB even if lesser alignment values are
-detected. In either case, it can be changed by using this option.
+physical sectors (such as modern Advanced Format drives), some RAID
+configurations, and many SSD devices, can suffer performance problems if
+partitions are not aligned properly for their internal data structures. On
+new disks, GPT fdisk attempts to align partitions on 2048\-sector (1MiB)
+boundaries by default, which optimizes performance for all of these disk
+types. On pre\-partitioned disks, GPT fdisk attempts to identify the
+alignment value used on that disk, but will set 8-sector alignment on disks
+larger than 300 GB even if lesser alignment values are detected. In either
+case, it can be changed by using this option.
.TP
.B m
@@ -561,7 +561,7 @@ entering data. When only one option is possible, \fBgdisk\fR
usually bypasses the prompt entirely.
.SH "BUGS"
-As of June 2011 (version 0.7.2), \fBgdisk\fR
+As of September 2011 (version 0.8.0), \fBgdisk\fR
should be considered beta software. Known bugs and limitations include:
.TP
@@ -649,10 +649,6 @@ options in this case.
.PP
-The support for big\-endian CPUs (PowerPC, for example) is new, as of
-version 0.3.5. I advise using caution on such CPUs, particularly with the
-more obscure features of the program.
-
.SH "AUTHORS"
Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
@@ -671,6 +667,7 @@ Contributors:
.SH "SEE ALSO"
\fBcfdisk (8)\fR,
+\fBcgdisk (8)\fR,
\fBfdisk (8)\fR,
\fBmkfs (8)\fR,
\fBparted (8)\fR,
diff --git a/gdisk.cc b/gdisk.cc
index 98d4980..05f1bd0 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -7,24 +7,9 @@
/* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
-#include <stdio.h>
#include <string.h>
-#include <string>
#include <iostream>
-#include <sstream>
-#include <locale>
-#include "mbr.h"
#include "gpttext.h"
-#include "support.h"
-
-// Function prototypes....
-void MainMenu(string filename, GPTDataTextUI* theGPT);
-void ShowCommands(void);
-void ExpertsMenu(string filename, GPTDataTextUI* theGPT);
-void ShowExpertCommands(void);
-void RecoveryMenu(string filename, GPTDataTextUI* theGPT);
-void ShowRecoveryCommands(void);
-void WinWarning(void);
int main(int argc, char* argv[]) {
GPTDataTextUI theGPT;
@@ -45,14 +30,14 @@ int main(int argc, char* argv[]) {
else if (theGPT.LoadPartitions(device)) {
if (theGPT.GetState() != use_gpt)
WinWarning();
- MainMenu(device, &theGPT);
+ theGPT.MainMenu(device);
} // if/elseif
break;
case 2: // basic usage
if (theGPT.LoadPartitions(argv[1])) {
if (theGPT.GetState() != use_gpt)
WinWarning();
- MainMenu(argv[1], &theGPT);
+ theGPT.MainMenu(argv[1]);
} // if
break;
case 3: // usage with "-l" option
@@ -73,374 +58,4 @@ int main(int argc, char* argv[]) {
cerr << "Usage: " << argv[0] << " [-l] device_file\n";
break;
} // switch
-} // main
-
-// Accept a command and execute it. Returns only when the user
-// wants to exit (such as after a 'w' or 'q' command).
-void MainMenu(string filename, GPTDataTextUI* theGPT) {
- int goOn = 1;
- PartType typeHelper;
- uint32_t temp1, temp2;
-
- do {
- cout << "\nCommand (? for help): ";
- switch (ReadString()[0]) {
- case '\0':
- break;
- case 'b': case 'B':
- cout << "Enter backup filename to save: ";
- theGPT->SaveGPTBackup(ReadString());
- break;
- case 'c': case 'C':
- if (theGPT->GetPartRange(&temp1, &temp2) > 0)
- theGPT->SetName(theGPT->GetPartNum());
- else
- cout << "No partitions\n";
- break;
- case 'd': case 'D':
- theGPT->DeletePartition();
- break;
- case 'i': case 'I':
- theGPT->ShowDetails();
- break;
- case 'l': case 'L':
- typeHelper.ShowAllTypes();
- break;
- case 'n': case 'N':
- theGPT->CreatePartition();
- break;
- case 'o': case 'O':
- cout << "This option deletes all partitions and creates a new protective MBR.\n"
- << "Proceed? ";
- if (GetYN() == 'Y') {
- theGPT->ClearGPTData();
- theGPT->MakeProtectiveMBR();
- } // if
- break;
- case 'p': case 'P':
- theGPT->DisplayGPTData();
- break;
- case 'q': case 'Q':
- goOn = 0;
- break;
- case 'r': case 'R':
- RecoveryMenu(filename, theGPT);
- goOn = 0;
- break;
- case 's': case 'S':
- theGPT->SortGPT();
- cout << "You may need to edit /etc/fstab and/or your boot loader configuration!\n";
- break;
- case 't': case 'T':
- theGPT->ChangePartType();
- break;
- case 'v': case 'V':
- theGPT->Verify();
- break;
- case 'w': case 'W':
- if (theGPT->SaveGPTData() == 1)
- goOn = 0;
- break;
- case 'x': case 'X':
- ExpertsMenu(filename, theGPT);
- goOn = 0;
- break;
- default:
- ShowCommands();
- break;
- } // switch
- } while (goOn);
-} // MainMenu()
-
-void ShowCommands(void) {
- cout << "b\tback up GPT data to a file\n";
- cout << "c\tchange a partition's name\n";
- cout << "d\tdelete a partition\n";
- cout << "i\tshow detailed information on a partition\n";
- cout << "l\tlist known partition types\n";
- cout << "n\tadd a new partition\n";
- cout << "o\tcreate a new empty GUID partition table (GPT)\n";
- cout << "p\tprint the partition table\n";
- cout << "q\tquit without saving changes\n";
- cout << "r\trecovery and transformation options (experts only)\n";
- cout << "s\tsort partitions\n";
- cout << "t\tchange a partition's type code\n";
- cout << "v\tverify disk\n";
- cout << "w\twrite table to disk and exit\n";
- cout << "x\textra functionality (experts only)\n";
- cout << "?\tprint this menu\n";
-} // ShowCommands()
-
-// Accept a recovery & transformation menu command. Returns only when the user
-// issues an exit command, such as 'w' or 'q'.
-void RecoveryMenu(string filename, GPTDataTextUI* theGPT) {
- uint32_t numParts;
- int goOn = 1, temp1;
-
- do {
- cout << "\nRecovery/transformation command (? for help): ";
- switch (ReadString()[0]) {
- case '\0':
- break;
- case 'b': case 'B':
- theGPT->RebuildMainHeader();
- break;
- case 'c': case 'C':
- cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
- << "GPT form and haven't yet saved the GPT! Proceed? ";
- if (GetYN() == 'Y')
- theGPT->LoadSecondTableAsMain();
- break;
- case 'd': case 'D':
- theGPT->RebuildSecondHeader();
- break;
- case 'e': case 'E':
- cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
- << "GPT form and haven't yet saved the GPT! Proceed? ";
- if (GetYN() == 'Y')
- theGPT->LoadMainTable();
- break;
- case 'f': case 'F':
- cout << "Warning! This will destroy the currently defined partitions! Proceed? ";
- if (GetYN() == 'Y') {
- if (theGPT->LoadMBR(filename) == 1) { // successful load
- theGPT->XFormPartitions();
- } else {
- cout << "Problem loading MBR! GPT is untouched; regenerating protective MBR!\n";
- theGPT->MakeProtectiveMBR();
- } // if/else
- } // if
- break;
- case 'g': case 'G':
- numParts = theGPT->GetNumParts();
- temp1 = theGPT->XFormToMBR();
- if (temp1 > 0)
- cout << "\nConverted " << temp1 << " partitions. Finalize and exit? ";
- if ((temp1 > 0) && (GetYN() == 'Y')) {
- if ((theGPT->DestroyGPT() > 0) && (theGPT->SaveMBR())) {
- goOn = 0;
- } // if
- } else {
- theGPT->MakeProtectiveMBR();
- theGPT->SetGPTSize(numParts);
- cout << "Note: New protective MBR created\n\n";
- } // if/else
- break;
- case 'h': case 'H':
- theGPT->MakeHybrid();
- break;
- case 'i': case 'I':
- theGPT->ShowDetails();
- break;
- case 'l': case 'L':
- cout << "Enter backup filename to load: ";
- theGPT->LoadGPTBackup(ReadString());
- break;
- case 'm': case 'M':
- MainMenu(filename, theGPT);
- goOn = 0;
- break;
- case 'o': case 'O':
- theGPT->DisplayMBRData();
- break;
- case 'p': case 'P':
- theGPT->DisplayGPTData();
- break;
- case 'q': case 'Q':
- goOn = 0;
- break;
- case 't': case 'T':
- theGPT->XFormDisklabel();
- break;
- case 'v': case 'V':
- theGPT->Verify();
- break;
- case 'w': case 'W':
- if (theGPT->SaveGPTData() == 1) {
- goOn = 0;
- } // if
- break;
- case 'x': case 'X':
- ExpertsMenu(filename, theGPT);
- goOn = 0;
- break;
- default:
- ShowRecoveryCommands();
- break;
- } // switch
- } while (goOn);
-} // RecoveryMenu()
-
-void ShowRecoveryCommands(void) {
- cout << "b\tuse backup GPT header (rebuilding main)\n";
- cout << "c\tload backup partition table from disk (rebuilding main)\n";
- cout << "d\tuse main GPT header (rebuilding backup)\n";
- cout << "e\tload main partition table from disk (rebuilding backup)\n";
- cout << "f\tload MBR and build fresh GPT from it\n";
- cout << "g\tconvert GPT into MBR and exit\n";
- cout << "h\tmake hybrid MBR\n";
- cout << "i\tshow detailed information on a partition\n";
- cout << "l\tload partition data from a backup file\n";
- cout << "m\treturn to main menu\n";
- cout << "o\tprint protective MBR data\n";
- cout << "p\tprint the partition table\n";
- cout << "q\tquit without saving changes\n";
- cout << "t\ttransform BSD disklabel partition\n";
- cout << "v\tverify disk\n";
- cout << "w\twrite table to disk and exit\n";
- cout << "x\textra functionality (experts only)\n";
- cout << "?\tprint this menu\n";
-} // ShowRecoveryCommands()
-
-// Accept an experts' menu command. Returns only after the user
-// selects an exit command, such as 'w' or 'q'.
-void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
- GPTData secondDevice;
- uint32_t temp1, temp2;
- int goOn = 1;
- string guidStr, device;
- GUIDData aGUID;
- ostringstream prompt;
-
- do {
- cout << "\nExpert command (? for help): ";
- switch (ReadString()[0]) {
- case '\0':
- break;
- case 'a': case 'A':
- if (theGPT->GetPartRange(&temp1, &temp2) > 0)
- theGPT->SetAttributes(theGPT->GetPartNum());
- else
- cout << "No partitions\n";
- break;
- case 'c': case 'C':
- theGPT->ChangeUniqueGuid();
- break;
- case 'd': case 'D':
- cout << "Partitions will begin on " << theGPT->GetAlignment()
- << "-sector boundaries.\n";
- break;
- case 'e': case 'E':
- cout << "Relocating backup data structures to the end of the disk\n";
- theGPT->MoveSecondHeaderToEnd();
- break;
- case 'f': case 'F':
- theGPT->RandomizeGUIDs();
- break;
- case 'g': case 'G':
- cout << "Enter the disk's unique GUID ('R' to randomize): ";
- guidStr = ReadString();
- if ((guidStr.length() >= 32) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
- theGPT->SetDiskGUID((GUIDData) guidStr);
- cout << "The new disk GUID is " << theGPT->GetDiskGUID() << "\n";
- } else {
- cout << "GUID is too short!\n";
- } // if/else
- break;
- case 'h': case 'H':
- theGPT->RecomputeCHS();
- break;
- case 'i': case 'I':
- theGPT->ShowDetails();
- break;
- case 'l': case 'L':
- prompt.seekp(0);
- prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = "
- << DEFAULT_ALIGNMENT << "): ";
- temp1 = GetNumber(1, MAX_ALIGNMENT, DEFAULT_ALIGNMENT, prompt.str());
- theGPT->SetAlignment(temp1);
- break;
- case 'm': case 'M':
- MainMenu(filename, theGPT);
- goOn = 0;
- break;
- case 'n': case 'N':
- theGPT->MakeProtectiveMBR();
- break;
- case 'o': case 'O':
- theGPT->DisplayMBRData();
- break;
- case 'p': case 'P':
- theGPT->DisplayGPTData();
- break;
- case 'q': case 'Q':
- goOn = 0;
- break;
- case 'r': case 'R':
- RecoveryMenu(filename, theGPT);
- goOn = 0;
- break;
- case 's': case 'S':
- theGPT->ResizePartitionTable();
- break;
- case 't': case 'T':
- theGPT->SwapPartitions();
- break;
- case 'u': case 'U':
- cout << "Type device filename, or press <Enter> to exit: ";
- device = ReadString();
- if (device.length() > 0) {
- secondDevice = *theGPT;
- secondDevice.SetDisk(device);
- secondDevice.SaveGPTData(0);
- } // if
- break;
- case 'v': case 'V':
- theGPT->Verify();
- break;
- case 'w': case 'W':
- if (theGPT->SaveGPTData() == 1) {
- goOn = 0;
- } // if
- break;
- case 'z': case 'Z':
- if (theGPT->DestroyGPTwPrompt() == 1) {
- goOn = 0;
- }
- break;
- default:
- ShowExpertCommands();
- break;
- } // switch
- } while (goOn);
-} // ExpertsMenu()
-
-void ShowExpertCommands(void) {
- cout << "a\tset attributes\n";
- cout << "c\tchange partition GUID\n";
- cout << "d\tdisplay the sector alignment value\n";
- cout << "e\trelocate backup data structures to the end of the disk\n";
- cout << "g\tchange disk GUID\n";
- cout << "h\trecompute CHS values in protective/hybrid MBR\n";
- cout << "i\tshow detailed information on a partition\n";
- cout << "l\tset the sector alignment value\n";
- cout << "m\treturn to main menu\n";
- cout << "n\tcreate a new protective MBR\n";
- cout << "o\tprint protective MBR data\n";
- cout << "p\tprint the partition table\n";
- cout << "q\tquit without saving changes\n";
- cout << "r\trecovery and transformation options (experts only)\n";
- cout << "s\tresize partition table\n";
- cout << "t\ttranspose two partition table entries\n";
- cout << "u\tReplicate partition table on new device\n";
- cout << "v\tverify disk\n";
- cout << "w\twrite table to disk and exit\n";
- cout << "z\tzap (destroy) GPT data structures and exit\n";
- cout << "?\tprint this menu\n";
-} // ShowExpertCommands()
-
-// On Windows, display a warning and ask whether to continue. If the user elects
-// not to continue, exit immediately.
-void WinWarning(void) {
-#ifdef _WIN32
- cout << "\a************************************************************************\n"
- << "Most versions of Windows cannot boot from a GPT disk, and most varieties\n"
- << "prior to Vista cannot read GPT disks. Therefore, you should exit now\n"
- << "unless you understand the implications of converting MBR to GPT or creating\n"
- << "a new GPT disk layout!\n"
- << "************************************************************************\n\n";
- cout << "Are you SURE you want to continue? ";
- if (GetYN() != 'Y')
- exit(0);
-#endif
-} // WinWarning()
+} // main \ No newline at end of file
diff --git a/gpt.cc b/gpt.cc
index c28e39d..25ca53a 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -899,36 +899,41 @@ int GPTData::LoadPartitionTable(const struct GPTHeader & header, DiskIO & disk,
// Check the partition table pointed to by header, but don't keep it
// around.
-// Returns 1 if the CRC is OK, 0 if not or if there was a read error.
+// Returns 1 if the CRC is OK & this table matches the one already in memory,
+// 0 if not or if there was a read error.
int GPTData::CheckTable(struct GPTHeader *header) {
uint32_t sizeOfParts, newCRC;
- uint8_t *storage;
- int newCrcOk = 0;
+ GPTPart *partsToCheck;
+ int allOK = 0;
// Load partition table into temporary storage to check
// its CRC and store the results, then discard this temporary
// storage, since we don't use it in any but recovery operations
if (myDisk.Seek(header->partitionEntriesLBA)) {
+ partsToCheck = new GPTPart[header->numParts];
sizeOfParts = header->numParts * header->sizeOfPartitionEntries;
- storage = new uint8_t[sizeOfParts];
- if (storage == NULL) {
+ if (partsToCheck == NULL) {
cerr << "Could not allocate memory in GPTData::CheckTable()! Terminating!\n";
exit(1);
} // if
- if (myDisk.Read(storage, sizeOfParts) != (int) sizeOfParts) {
+ if (myDisk.Read(partsToCheck, sizeOfParts) != (int) sizeOfParts) {
cerr << "Warning! Error " << errno << " reading partition table for CRC check!\n";
} else {
- newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
- newCrcOk = (newCRC == header->partitionEntriesCRC);
+ newCRC = chksum_crc32((unsigned char*) partsToCheck, sizeOfParts);
+ allOK = (newCRC == header->partitionEntriesCRC);
+ if (memcmp(partitions, partsToCheck, sizeOfParts) != 0) {
+ cerr << "Warning! Main and backup partition tables differ! Use the 'c' and 'e' options\n"
+ << "on the recovery & transformation menu to examine the two tables.\n\n";
+ allOK = 0;
+ } // if
} // if/else
- delete[] storage;
+ delete[] partsToCheck;
} // if
- return newCrcOk;
+ return allOK;
} // GPTData::CheckTable()
// Writes GPT (and protective MBR) to disk. If quiet==1,
-// Returns 1 on successful
-// write, 0 if there was a problem.
+// Returns 1 on successful write, 0 if there was a problem.
int GPTData::SaveGPTData(int quiet) {
int allOK = 1, littleEndian;
char answer;
@@ -1227,7 +1232,7 @@ int GPTData::DestroyGPT(void) {
tableSize = numParts * mainHeader.sizeOfPartitionEntries;
emptyTable = new uint8_t[tableSize];
if (emptyTable == NULL) {
- cerr << "Could not allocate memory in GPTData::CheckTable()! Terminating!\n";
+ cerr << "Could not allocate memory in GPTData::DestroyGPT()! Terminating!\n";
exit(1);
} // if
memset(emptyTable, 0, tableSize);
diff --git a/gpttext.cc b/gpttext.cc
index 4db9e13..cd1c07a 100644
--- a/gpttext.cc
+++ b/gpttext.cc
@@ -33,11 +33,11 @@
using namespace std;
-/*******************************************
-* *
-* GPTDataText class and related structures *
-* *
-********************************************/
+/********************************************
+ * *
+ * GPTDataText class and related structures *
+ * *
+ ********************************************/
GPTDataTextUI::GPTDataTextUI(void) : GPTData() {
} // default constructor
@@ -141,7 +141,8 @@ int GPTDataTextUI::XFormDisklabel(void) {
* *
*********************************************************************/
-// Prompts user for partition number and returns the result.
+// Prompts user for partition number and returns the result. Returns "0"
+// (the first partition) if none are currently defined.
uint32_t GPTDataTextUI::GetPartNum(void) {
uint32_t partNum;
uint32_t low, high;
@@ -257,7 +258,6 @@ void GPTDataTextUI::DeletePartition(void) {
} // GPTDataTextUI::DeletePartition()
// Prompt user for a partition number, then change its type code
-// using ChangeGPTType(struct GPTPartition*) function.
void GPTDataTextUI::ChangePartType(void) {
int partNum;
uint32_t low, high;
@@ -494,6 +494,370 @@ int GPTDataTextUI::XFormToMBR(void) {
return protectiveMBR.DoMenu();
} // GPTDataTextUI::XFormToMBR()
+
+/*********************************************************************
+ * *
+ * The following functions provide the main menus for the gdisk *
+ * program.... *
+ * *
+ *********************************************************************/
+
+// Accept a command and execute it. Returns only when the user
+// wants to exit (such as after a 'w' or 'q' command).
+void GPTDataTextUI::MainMenu(string filename) {
+ int goOn = 1;
+ PartType typeHelper;
+ uint32_t temp1, temp2;
+
+ do {
+ cout << "\nCommand (? for help): ";
+ switch (ReadString()[0]) {
+ case '\0':
+ break;
+ case 'b': case 'B':
+ cout << "Enter backup filename to save: ";
+ SaveGPTBackup(ReadString());
+ break;
+ case 'c': case 'C':
+ if (GetPartRange(&temp1, &temp2) > 0)
+ SetName(GetPartNum());
+ else
+ cout << "No partitions\n";
+ break;
+ case 'd': case 'D':
+ DeletePartition();
+ break;
+ case 'i': case 'I':
+ ShowDetails();
+ break;
+ case 'l': case 'L':
+ typeHelper.ShowAllTypes();
+ break;
+ case 'n': case 'N':
+ CreatePartition();
+ break;
+ case 'o': case 'O':
+ cout << "This option deletes all partitions and creates a new protective MBR.\n"
+ << "Proceed? ";
+ if (GetYN() == 'Y') {
+ ClearGPTData();
+ MakeProtectiveMBR();
+ } // if
+ break;
+ case 'p': case 'P':
+ DisplayGPTData();
+ break;
+ case 'q': case 'Q':
+ goOn = 0;
+ break;
+ case 'r': case 'R':
+ RecoveryMenu(filename);
+ goOn = 0;
+ break;
+ case 's': case 'S':
+ SortGPT();
+ cout << "You may need to edit /etc/fstab and/or your boot loader configuration!\n";
+ break;
+ case 't': case 'T':
+ ChangePartType();
+ break;
+ case 'v': case 'V':
+ Verify();
+ break;
+ case 'w': case 'W':
+ if (SaveGPTData() == 1)
+ goOn = 0;
+ break;
+ case 'x': case 'X':
+ ExpertsMenu(filename);
+ goOn = 0;
+ break;
+ default:
+ ShowCommands();
+ break;
+ } // switch
+ } while (goOn);
+} // GPTDataTextUI::MainMenu()
+
+void GPTDataTextUI::ShowCommands(void) {
+ cout << "b\tback up GPT data to a file\n";
+ cout << "c\tchange a partition's name\n";
+ cout << "d\tdelete a partition\n";
+ cout << "i\tshow detailed information on a partition\n";
+ cout << "l\tlist known partition types\n";
+ cout << "n\tadd a new partition\n";
+ cout << "o\tcreate a new empty GUID partition table (GPT)\n";
+ cout << "p\tprint the partition table\n";
+ cout << "q\tquit without saving changes\n";
+ cout << "r\trecovery and transformation options (experts only)\n";
+ cout << "s\tsort partitions\n";
+ cout << "t\tchange a partition's type code\n";
+ cout << "v\tverify disk\n";
+ cout << "w\twrite table to disk and exit\n";
+ cout << "x\textra functionality (experts only)\n";
+ cout << "?\tprint this menu\n";
+} // GPTDataTextUI::ShowCommands()
+
+// Accept a recovery & transformation menu command. Returns only when the user
+// issues an exit command, such as 'w' or 'q'.
+void GPTDataTextUI::RecoveryMenu(string filename) {
+ uint32_t numParts;
+ int goOn = 1, temp1;
+
+ do {
+ cout << "\nRecovery/transformation command (? for help): ";
+ switch (ReadString()[0]) {
+ case '\0':
+ break;
+ case 'b': case 'B':
+ RebuildMainHeader();
+ break;
+ case 'c': case 'C':
+ cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
+ << "GPT form and haven't yet saved the GPT! Proceed? ";
+ if (GetYN() == 'Y')
+ LoadSecondTableAsMain();
+ break;
+ case 'd': case 'D':
+ RebuildSecondHeader();
+ break;
+ case 'e': case 'E':
+ cout << "Warning! This will probably do weird things if you've converted an MBR to\n"
+ << "GPT form and haven't yet saved the GPT! Proceed? ";
+ if (GetYN() == 'Y')
+ LoadMainTable();
+ break;
+ case 'f': case 'F':
+ cout << "Warning! This will destroy the currently defined partitions! Proceed? ";
+ if (GetYN() == 'Y') {
+ if (LoadMBR(filename) == 1) { // successful load
+ XFormPartitions();
+ } else {
+ cout << "Problem loading MBR! GPT is untouched; regenerating protective MBR!\n";
+ MakeProtectiveMBR();
+ } // if/else
+ } // if
+ break;
+ case 'g': case 'G':
+ numParts = GetNumParts();
+ temp1 = XFormToMBR();
+ if (temp1 > 0)
+ cout << "\nConverted " << temp1 << " partitions. Finalize and exit? ";
+ if ((temp1 > 0) && (GetYN() == 'Y')) {
+ if ((DestroyGPT() > 0) && (SaveMBR())) {
+ goOn = 0;
+ } // if
+ } else {
+ MakeProtectiveMBR();
+ SetGPTSize(numParts);
+ cout << "Note: New protective MBR created\n\n";
+ } // if/else
+ break;
+ case 'h': case 'H':
+ MakeHybrid();
+ break;
+ case 'i': case 'I':
+ ShowDetails();
+ break;
+ case 'l': case 'L':
+ cout << "Enter backup filename to load: ";
+ LoadGPTBackup(ReadString());
+ break;
+ case 'm': case 'M':
+ MainMenu(filename);
+ goOn = 0;
+ break;
+ case 'o': case 'O':
+ DisplayMBRData();
+ break;
+ case 'p': case 'P':
+ DisplayGPTData();
+ break;
+ case 'q': case 'Q':
+ goOn = 0;
+ break;
+ case 't': case 'T':
+ XFormDisklabel();
+ break;
+ case 'v': case 'V':
+ Verify();
+ break;
+ case 'w': case 'W':
+ if (SaveGPTData() == 1) {
+ goOn = 0;
+ } // if
+ break;
+ case 'x': case 'X':
+ ExpertsMenu(filename);
+ goOn = 0;
+ break;
+ default:
+ ShowRecoveryCommands();
+ break;
+ } // switch
+ } while (goOn);
+} // GPTDataTextUI::RecoveryMenu()
+
+void GPTDataTextUI::ShowRecoveryCommands(void) {
+ cout << "b\tuse backup GPT header (rebuilding main)\n";
+ cout << "c\tload backup partition table from disk (rebuilding main)\n";
+ cout << "d\tuse main GPT header (rebuilding backup)\n";
+ cout << "e\tload main partition table from disk (rebuilding backup)\n";
+ cout << "f\tload MBR and build fresh GPT from it\n";
+ cout << "g\tconvert GPT into MBR and exit\n";
+ cout << "h\tmake hybrid MBR\n";
+ cout << "i\tshow detailed information on a partition\n";
+ cout << "l\tload partition data from a backup file\n";
+ cout << "m\treturn to main menu\n";
+ cout << "o\tprint protective MBR data\n";
+ cout << "p\tprint the partition table\n";
+ cout << "q\tquit without saving changes\n";
+ cout << "t\ttransform BSD disklabel partition\n";
+ cout << "v\tverify disk\n";
+ cout << "w\twrite table to disk and exit\n";
+ cout << "x\textra functionality (experts only)\n";
+ cout << "?\tprint this menu\n";
+} // GPTDataTextUI::ShowRecoveryCommands()
+
+// Accept an experts' menu command. Returns only after the user
+// selects an exit command, such as 'w' or 'q'.
+void GPTDataTextUI::ExpertsMenu(string filename) {
+ GPTData secondDevice;
+ uint32_t temp1, temp2;
+ int goOn = 1;
+ string guidStr, device;
+ GUIDData aGUID;
+ ostringstream prompt;
+
+ do {
+ cout << "\nExpert command (? for help): ";
+ switch (ReadString()[0]) {
+ case '\0':
+ break;
+ case 'a': case 'A':
+ if (GetPartRange(&temp1, &temp2) > 0)
+ SetAttributes(GetPartNum());
+ else
+ cout << "No partitions\n";
+ break;
+ case 'c': case 'C':
+ ChangeUniqueGuid();
+ break;
+ case 'd': case 'D':
+ cout << "Partitions will begin on " << GetAlignment()
+ << "-sector boundaries.\n";
+ break;
+ case 'e': case 'E':
+ cout << "Relocating backup data structures to the end of the disk\n";
+ MoveSecondHeaderToEnd();
+ break;
+ case 'f': case 'F':
+ RandomizeGUIDs();
+ break;
+ case 'g': case 'G':
+ cout << "Enter the disk's unique GUID ('R' to randomize): ";
+ guidStr = ReadString();
+ if ((guidStr.length() >= 32) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
+ SetDiskGUID((GUIDData) guidStr);
+ cout << "The new disk GUID is " << GetDiskGUID() << "\n";
+ } else {
+ cout << "GUID is too short!\n";
+ } // if/else
+ break;
+ case 'h': case 'H':
+ RecomputeCHS();
+ break;
+ case 'i': case 'I':
+ ShowDetails();
+ break;
+ case 'l': case 'L':
+ prompt.seekp(0);
+ prompt << "Enter the sector alignment value (1-" << MAX_ALIGNMENT << ", default = "
+ << DEFAULT_ALIGNMENT << "): ";
+ temp1 = GetNumber(1, MAX_ALIGNMENT, DEFAULT_ALIGNMENT, prompt.str());
+ SetAlignment(temp1);
+ break;
+ case 'm': case 'M':
+ MainMenu(filename);
+ goOn = 0;
+ break;
+ case 'n': case 'N':
+ MakeProtectiveMBR();
+ break;
+ case 'o': case 'O':
+ DisplayMBRData();
+ break;
+ case 'p': case 'P':
+ DisplayGPTData();
+ break;
+ case 'q': case 'Q':
+ goOn = 0;
+ break;
+ case 'r': case 'R':
+ RecoveryMenu(filename);
+ goOn = 0;
+ break;
+ case 's': case 'S':
+ ResizePartitionTable();
+ break;
+ case 't': case 'T':
+ SwapPartitions();
+ break;
+ case 'u': case 'U':
+ cout << "Type device filename, or press <Enter> to exit: ";
+ device = ReadString();
+ if (device.length() > 0) {
+ secondDevice = *this;
+ secondDevice.SetDisk(device);
+ secondDevice.SaveGPTData(0);
+ } // if
+ break;
+ case 'v': case 'V':
+ Verify();
+ break;
+ case 'w': case 'W':
+ if (SaveGPTData() == 1) {
+ goOn = 0;
+ } // if
+ break;
+ case 'z': case 'Z':
+ if (DestroyGPTwPrompt() == 1) {
+ goOn = 0;
+ }
+ break;
+ default:
+ ShowExpertCommands();
+ break;
+ } // switch
+ } while (goOn);
+} // GPTDataTextUI::ExpertsMenu()
+
+void GPTDataTextUI::ShowExpertCommands(void) {
+ cout << "a\tset attributes\n";
+ cout << "c\tchange partition GUID\n";
+ cout << "d\tdisplay the sector alignment value\n";
+ cout << "e\trelocate backup data structures to the end of the disk\n";
+ cout << "g\tchange disk GUID\n";
+ cout << "h\trecompute CHS values in protective/hybrid MBR\n";
+ cout << "i\tshow detailed information on a partition\n";
+ cout << "l\tset the sector alignment value\n";
+ cout << "m\treturn to main menu\n";
+ cout << "n\tcreate a new protective MBR\n";
+ cout << "o\tprint protective MBR data\n";
+ cout << "p\tprint the partition table\n";
+ cout << "q\tquit without saving changes\n";
+ cout << "r\trecovery and transformation options (experts only)\n";
+ cout << "s\tresize partition table\n";
+ cout << "t\ttranspose two partition table entries\n";
+ cout << "u\tReplicate partition table on new device\n";
+ cout << "v\tverify disk\n";
+ cout << "w\twrite table to disk and exit\n";
+ cout << "z\tzap (destroy) GPT data structures and exit\n";
+ cout << "?\tprint this menu\n";
+} // GPTDataTextUI::ShowExpertCommands()
+
+
+
/********************************
* *
* Non-class support functions. *
diff --git a/gpttext.h b/gpttext.h
index 553efa2..1c74105 100644
--- a/gpttext.h
+++ b/gpttext.h
@@ -1,5 +1,5 @@
/*
- <one line to give the program's name and a brief idea of what it does.>
+ Implementation of GPTData class derivative with basic text-mode interaction
Copyright (C) 2010-2011 Roderick W. Smith
This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@ class GPTDataTextUI : public GPTData {
~GPTDataTextUI(void);
// This one needs to be explicitly defined, even though it does nothing new....
- const GPTPart & operator[](uint32_t partNum) {return GPTData::operator[](partNum);}
+// const GPTPart & operator[](uint32_t partNum) {return GPTData::operator[](partNum);}
// Extended (interactive) versions of some base-class functions
WhichToUse UseWhichPartitions(void);
@@ -53,6 +53,14 @@ class GPTDataTextUI : public GPTData {
void ShowDetails(void);
void MakeHybrid(void);
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
+
+ // Main menu functions
+ void MainMenu(string filename);
+ void ShowCommands(void);
+ void ExpertsMenu(string filename);
+ void ShowExpertCommands(void);
+ void RecoveryMenu(string filename);
+ void ShowRecoveryCommands(void);
}; // class GPTDataTextUI
int GetMBRTypeCode(int defType);
diff --git a/mbrpart.cc b/mbrpart.cc
index c721f3f..e9240a1 100644
--- a/mbrpart.cc
+++ b/mbrpart.cc
@@ -121,10 +121,11 @@ bool MBRPart::operator<(const MBRPart &other) const {
* *
**************************************************/
-void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t diskSize,
- uint32_t blockSize) {
+void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t ds, uint32_t bs) {
numHeads = heads;
numSecspTrack = sectors;
+ diskSize = ds;
+ blockSize = bs;
} // MBRPart::SetGeometry
// Empty the partition (zero out all values).
@@ -173,20 +174,23 @@ void MBRPart::SetLengthLBA(uint64_t length) {
// values, sets them directly, and sets the CHS values based on the LBA
// values and the current geometry settings.
void MBRPart::SetLocation(uint64_t start, uint64_t length) {
+ int validCHS;
+
if ((start > UINT32_MAX) || (length > UINT32_MAX)) {
cerr << "Partition values out of range in MBRPart::SetLocation()!\n"
<< "Continuing, but strange problems are now likely!\n";
} // if
firstLBA = (uint32_t) start;
lengthLBA = (uint32_t) length;
- RecomputeCHS();
+ validCHS = RecomputeCHS();
// If this is a complete 0xEE protective MBR partition, max out its
// CHS last sector value, as per the GPT spec. (Set to 0xffffff,
// although the maximum legal MBR value is 0xfeffff, which is
// actually what GNU Parted and Apple's Disk Utility use, in
// violation of the GPT spec.)
- if ((partitionType == 0xEE) && (firstLBA == 1) && (lengthLBA == diskSize - 2)) {
+ if ((partitionType == 0xEE) && (!validCHS) && (firstLBA == 1) &&
+ ((lengthLBA == diskSize - 1) || (lengthLBA == UINT32_MAX))) {
lastSector[0] = lastSector[1] = lastSector[2] = 0xFF;
} // if
} // MBRPart::SetLocation()
@@ -234,11 +238,17 @@ int MBRPart::DoTheyOverlap (const MBRPart& other) {
* *
*************************************************/
-void MBRPart::RecomputeCHS(void) {
+// Recompute the CHS values for the start and end points.
+// Returns 1 if both computed values are within the range
+// that can be expressed by that CHS, 0 otherwise.
+int MBRPart::RecomputeCHS(void) {
+ int retval = 1;
+
if (lengthLBA > 0) {
- LBAtoCHS(firstLBA, firstSector);
- LBAtoCHS(firstLBA + lengthLBA - 1, lastSector);
+ retval = LBAtoCHS(firstLBA, firstSector);
+ retval *= LBAtoCHS(firstLBA + lengthLBA - 1, lastSector);
} // if
+ return retval;
} // MBRPart::RecomputeCHS()
// Converts 32-bit LBA value to MBR-style CHS value. Returns 1 if conversion
diff --git a/mbrpart.h b/mbrpart.h
index 0e3e775..f5892e7 100644
--- a/mbrpart.h
+++ b/mbrpart.h
@@ -77,7 +77,7 @@ public:
bool operator<(const MBRPart &other) const;
// Set information on partitions or disks...
- void SetGeometry(uint32_t heads, uint32_t sectors, uint64_t diskSize, uint32_t blockSize);
+ void SetGeometry(uint32_t heads, uint32_t sectors, uint64_t ds, uint32_t bs);
void Empty(void);
void SetStartLBA(uint64_t s);
void SetLengthLBA(uint64_t l);
@@ -101,7 +101,7 @@ public:
int DoTheyOverlap (const MBRPart& other);
// Adjust information on partitions or disks...
- void RecomputeCHS(void);
+ int RecomputeCHS(void);
int LBAtoCHS(uint32_t lba, uint8_t * chs);
void ReverseByteOrder(void);
diff --git a/parttypes.cc b/parttypes.cc
index d77774d..96bf5e9 100644
--- a/parttypes.cc
+++ b/parttypes.cc
@@ -108,7 +108,6 @@ void PartType::AddAllTypes(void) {
// Linux-specific partition types....
AddType(0x8200, "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", "Linux swap"); // Linux swap (or Solaris)
AddType(0x8300, "0FC63DAF-8483-4772-8E79-3D69D8477DE4", "Linux filesystem"); // Linux native
-// AddType(0x8300, "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7", "Linux/Windows data", 0); // Linux native
AddType(0x8301, "8DA63339-0007-60C0-C436-083AC8230908", "Linux reserved");
AddType(0x8e00, "E6D6D379-F507-44C2-A23C-238F2A3DF928", "Linux LVM");
@@ -142,6 +141,7 @@ void PartType::AddAllTypes(void) {
AddType(0xaf02, "52414944-5F4F-11AA-AA11-00306543ECAC", "Apple RAID offline");
AddType(0xaf03, "4C616265-6C00-11AA-AA11-00306543ECAC", "Apple label");
AddType(0xaf04, "5265636F-7665-11AA-AA11-00306543ECAC", "AppleTV recovery");
+ AddType(0xaf05, "53746F72-6167-11AA-AA11-00306543ECAC", "Apple Core Storage");
// Solaris partition types (one of which is shared with MacOS)
AddType(0xbe00, "6A82CB45-1DD2-11B2-99A6-080020736631", "Solaris boot");
@@ -214,7 +214,7 @@ PartType & PartType::operator=(const string & orig) {
if (IsHex(orig)) {
sscanf(orig.c_str(), "%x", &hexCode);
*this = hexCode;
- } // if
+ }
} else {
GUIDData::operator=(orig);
} // if/else hexCode or GUID
diff --git a/sgdisk.8 b/sgdisk.8
index 1fa5f77..3baed08 100644
--- a/sgdisk.8
+++ b/sgdisk.8
@@ -1,6 +1,6 @@
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
-.TH "SGDISK" "8" "0.7.2" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "SGDISK" "8" "0.8.0" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS"
@@ -89,7 +89,7 @@ and in whatever sizes are desired.
.B *
Boot disks for EFI\-based systems require an \fIEFI System
Partition\fR (\fBsgdisk\fR internal code 0xEF00) formatted as FAT\-32.
-The recommended size of this partition is between 100 and 200 MiB.
+The recommended size of this partition is between 100 and 300 MiB.
Boot\-related files are stored here. (Note that GNU Parted identifies
such partitions as having the "boot flag" set.)
@@ -151,7 +151,8 @@ Set the sector alignment multiple. GPT fdisk aligns the start of partitions
to sectors that are multiples of this value, which defaults to 2048 on
freshly formatted disks. This alignment value is necessary to obtain optimum
performance with Western Digital Advanced Format and similar drives with larger
-physical than logical sector sizes and with some types of RAID arrays.
+physical than logical sector sizes, with some types of RAID arrays, and
+with SSD devices.
.TP
.B \-A, \-\-attributes=list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]
@@ -282,7 +283,9 @@ displays this information for a single partition.
.B \-l, \-\-load\-backup=file
Load partition data from a backup file. This option is the reverse of the
\fI\-b\fR option. Note that restoring partition data from anything
-but the original disk is not recommended.
+but the original disk is not recommended. This option will work even if the
+disk's original partition table is bad; however, most other options on the
+same command line will be ignored.
.TP
.B \-L, \-\-list\-types
@@ -340,8 +343,13 @@ use the first available partition number.
.TP
.B \-o, \-\-clear
-Clear out all partition data. This includes GPT header data,
-all partition definitions, and the protective MBR.
+Clear out all partition data. This includes GPT header data, all partition
+definitions, and the protective MBR. Note that this operation will, like
+most other operations, fail on a damaged disk. If you want to prepare a
+disk you know to be damaged for GPT use, you should first wipe it with -Z
+and then partition it normally. This option will work even if the
+disk's original partition table is bad; however, most other options on the
+same command line will be ignored.
.TP
.B \-p, \-\-print
@@ -415,9 +423,11 @@ Print a brief summary of available options.
.B \-v, \-\-verify
Verify disk. This option checks for a variety of problems, such as
incorrect CRCs and mismatched main and backup data. This option does not
-automatically correct most problems, though; for that, you must use
-options on the recovery & transformation menu. If no problems are found,
-this command displays a summary of unallocated disk space.
+automatically correct most problems, though; for that, you must use options
+on the recovery & transformation menu. If no problems are found, this
+command displays a summary of unallocated disk space. This option will work
+even if the disk's original partition table is bad; however, most other
+options on the same command line will be ignored.
.TP
.B \-V, \-\-version
@@ -469,8 +479,13 @@ Non\-GPT disk detected and no \fI\-g\fR option
.TP
.B 4
An error prevented saving changes
+
+.TP
+.B 8
+Disk replication operation (-R) failed
+
.SH "BUGS"
-As of June 2011 (version 0.7.2), \fBsgdisk\fR
+As of September 2011 (version 0.8.0), \fBsgdisk\fR
should be considered beta software. Known bugs and limitations include:
.TP
@@ -544,11 +559,7 @@ from GPT disks. Creating a hybrid MBR (using the 'h' option on the recovery &
transformation menu) or abandoning GPT in favor of MBR may be your only
options in this case.
-.PP
-
-The support for big\-endian CPUs (PowerPC, for example) is new, as of
-version 0.3.5. I advise using caution on such systems, particularly with
-the more obscure features of the program.
+.PP
.SH "AUTHORS"
Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
@@ -568,6 +579,7 @@ Contributors:
.SH "SEE ALSO"
\fBcfdisk (8)\fR,
+\fBcgdisk (8)\fR,
\fBfdisk (8)\fR,
\fBgdisk (8)\fR,
\fBmkfs (8)\fR,
diff --git a/sgdisk.cc b/sgdisk.cc
index 6b9429b..d3fe1a8 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -9,513 +9,13 @@
/* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
-#include <stdio.h>
-#include <popt.h>
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <string>
-#include <iostream>
-#include <sstream>
-#include "mbr.h"
-#include "gpt.h"
-#include "support.h"
-#include "parttypes.h"
-#include "attributes.h"
+#include "gptcl.h"
using namespace std;
#define MAX_OPTIONS 50
-int BuildMBR(GPTData& theGPT, char* argument, int isHybrid);
-int CountColons(char* argument);
-
-// Extract colon-separated fields from a string....
-uint64_t GetInt(const string & argument, int itemNum);
-string GetString(string argument, int itemNum);
-
-
int main(int argc, char *argv[]) {
- GPTData theGPT, secondDevice;
- uint32_t sSize;
- uint64_t low, high;
- int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
- int partNum = 0, deletePartNum = 0, infoPartNum = 0, bsdPartNum = 0, largestPartNum = 0;
- int saveNonGPT = 1;
- uint32_t gptPartNum = 0;
- int alignment = DEFAULT_ALIGNMENT, retval = 0, pretend = 0;
- uint32_t tableSize = 128;
- uint64_t startSector, endSector;
- uint64_t temp; // temporary variable; free to use in any case
- char *attributeOperation = NULL;
- char *device;
- char *newPartInfo = NULL, *typeCode = NULL, *partName = NULL;
- char *backupFile = NULL, *twoParts = NULL, *hybrids = NULL, *mbrParts;
- char *partGUID = NULL, *diskGUID = NULL, *outDevice = NULL;
- string cmd, typeGUID, name;
- PartType typeHelper;
-
- poptContext poptCon;
- struct poptOption theOptions[] =
- {
- {"attributes", 'A', POPT_ARG_STRING, &attributeOperation, 'A', "operate on partition attributes", "list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]"},
- {"set-alignment", 'a', POPT_ARG_INT, &alignment, 'a', "set sector alignment", "value"},
- {"backup", 'b', POPT_ARG_STRING, &backupFile, 'b', "backup GPT to file", "file"},
- {"change-name", 'c', POPT_ARG_STRING, &partName, 'c', "change partition's name", "partnum:name"},
- {"recompute-chs", 'C', POPT_ARG_NONE, NULL, 'C', "recompute CHS values in protective/hybrid MBR", ""},
- {"delete", 'd', POPT_ARG_INT, &deletePartNum, 'd', "delete a partition", "partnum"},
- {"display-alignment", 'D', POPT_ARG_NONE, NULL, 'D', "show number of sectors per allocation block", ""},
- {"move-second-header", 'e', POPT_ARG_NONE, NULL, 'e', "move second header to end of disk", ""},
- {"end-of-largest", 'E', POPT_ARG_NONE, NULL, 'E', "show end of largest free block", ""},
- {"first-in-largest", 'f', POPT_ARG_NONE, NULL, 'f', "show start of the largest free block", ""},
- {"first-aligned-in-largest", 'F', POPT_ARG_NONE, NULL, 'F', "show start of the largest free block, aligned", ""},
- {"mbrtogpt", 'g', POPT_ARG_NONE, NULL, 'g', "convert MBR to GPT", ""},
- {"randomize-guids", 'G', POPT_ARG_NONE, NULL, 'G', "randomize disk and partition GUIDs", ""},
- {"hybrid", 'h', POPT_ARG_STRING, &hybrids, 'h', "create hybrid MBR", "partnum[:partnum...]"},
- {"info", 'i', POPT_ARG_INT, &infoPartNum, 'i', "show detailed information on partition", "partnum"},
- {"load-backup", 'l', POPT_ARG_STRING, &backupFile, 'l', "load GPT backup from file", "file"},
- {"list-types", 'L', POPT_ARG_NONE, NULL, 'L', "list known partition types", ""},
- {"gpttombr", 'm', POPT_ARG_STRING, &mbrParts, 'm', "convert GPT to MBR", "partnum[:partnum...]"},
- {"new", 'n', POPT_ARG_STRING, &newPartInfo, 'n', "create new partition", "partnum:start:end"},
- {"largest-new", 'N', POPT_ARG_INT, &largestPartNum, 'N', "create largest possible new partition", "partnum"},
- {"clear", 'o', POPT_ARG_NONE, NULL, 'o', "clear partition table", ""},
- {"print", 'p', POPT_ARG_NONE, NULL, 'p', "print partition table", ""},
- {"pretend", 'P', POPT_ARG_NONE, NULL, 'P', "make changes in memory, but don't write them", ""},
- {"transpose", 'r', POPT_ARG_STRING, &twoParts, 'r', "transpose two partitions", "partnum:partnum"},
- {"replicate", 'R', POPT_ARG_STRING, &outDevice, 'R', "replicate partition table", "device_filename"},
- {"sort", 's', POPT_ARG_NONE, NULL, 's', "sort partition table entries", ""},
- {"resize-table", 'S', POPT_ARG_INT, &tableSize, 'S', "resize partition table", "numparts"},
- {"typecode", 't', POPT_ARG_STRING, &typeCode, 't', "change partition type code", "partnum:{hexcode|GUID}"},
- {"transform-bsd", 'T', POPT_ARG_INT, &bsdPartNum, 'T', "transform BSD disklabel partition to GPT", "partnum"},
- {"partition-guid", 'u', POPT_ARG_STRING, &partGUID, 'u', "set partition GUID", "partnum:guid"},
- {"disk-guid", 'U', POPT_ARG_STRING, &diskGUID, 'U', "set disk GUID", "guid"},
- {"verify", 'v', POPT_ARG_NONE, NULL, 'v', "check partition table integrity", ""},
- {"version", 'V', POPT_ARG_NONE, NULL, 'V', "display version information", ""},
- {"zap", 'z', POPT_ARG_NONE, NULL, 'z', "zap (destroy) GPT (but not MBR) data structures", ""},
- {"zap-all", 'Z', POPT_ARG_NONE, NULL, 'Z', "zap (destroy) GPT and MBR data structures", ""},
- POPT_AUTOHELP { NULL, 0, 0, NULL, 0 }
- };
-
- // Create popt context...
- poptCon = poptGetContext(NULL, argc, (const char**) argv, theOptions, 0);
-
- poptSetOtherOptionHelp(poptCon, " [OPTION...] <device>");
-
- if (argc < 2) {
- poptPrintUsage(poptCon, stderr, 0);
- exit(1);
- }
-
- // Do one loop through the options to find the device filename and deal
- // with options that don't require a device filename....
- while ((opt = poptGetNextOpt(poptCon)) > 0) {
- switch (opt) {
- case 'A':
- cmd = GetString(attributeOperation, 1);
- if (cmd == "list")
- Attributes::ListAttributes();
- break;
- case 'L':
- typeHelper.ShowAllTypes();
- break;
- case 'P':
- pretend = 1;
- break;
- case 'V':
- cout << "GPT fdisk (sgdisk) version " << GPTFDISK_VERSION << "\n\n";
- break;
- default:
- break;
- } // switch
- numOptions++;
- } // while
-
- // Assume first non-option argument is the device filename....
- device = (char*) poptGetArg(poptCon);
- poptResetContext(poptCon);
-
- if (device != NULL) {
- theGPT.JustLooking(); // reset as necessary
- theGPT.BeQuiet(); // Tell called functions to be less verbose & interactive
- if (theGPT.LoadPartitions((string) device)) {
- if ((theGPT.WhichWasUsed() == use_mbr) || (theGPT.WhichWasUsed() == use_bsd))
- saveNonGPT = 0; // flag so we don't overwrite unless directed to do so
- sSize = theGPT.GetBlockSize();
- while ((opt = poptGetNextOpt(poptCon)) > 0) {
- switch (opt) {
- case 'A': {
- if (cmd != "list") {
- partNum = (int) GetInt(attributeOperation, 1) - 1;
- if ((partNum >= 0) && (partNum < (int) theGPT.GetNumParts())) {
- switch (theGPT.ManageAttributes(partNum, GetString(attributeOperation, 2),
- GetString(attributeOperation, 3))) {
- case -1:
- saveData = 0;
- neverSaveData = 1;
- break;
- case 1:
- theGPT.JustLooking(0);
- saveData = 1;
- break;
- default:
- break;
- } // switch
- } else {
- cerr << "Error: Invalid partition number " << partNum + 1 << "\n";
- saveData = 0;
- neverSaveData = 1;
- } // if/else reasonable partition #
- } // if (cmd != "list")
- break;
- } // case 'A':
- case 'a':
- theGPT.SetAlignment(alignment);
- break;
- case 'b':
- theGPT.SaveGPTBackup(backupFile);
- free(backupFile);
- break;
- case 'c':
- theGPT.JustLooking(0);
- partNum = (int) GetInt(partName, 1) - 1;
- name = GetString(partName, 2);
- if (theGPT.SetName(partNum, (UnicodeString) name.c_str())) {
- saveData = 1;
- } else {
- cerr << "Unable to set partition " << partNum + 1
- << "'s name to '" << GetString(partName, 2) << "'!\n";
- neverSaveData = 1;
- } // if/else
- free(partName);
- break;
- case 'C':
- theGPT.JustLooking(0);
- theGPT.RecomputeCHS();
- saveData = 1;
- break;
- case 'd':
- theGPT.JustLooking(0);
- if (theGPT.DeletePartition(deletePartNum - 1) == 0) {
- cerr << "Error " << errno << " deleting partition!\n";
- neverSaveData = 1;
- } else saveData = 1;
- break;
- case 'D':
- cout << theGPT.GetAlignment() << "\n";
- break;
- case 'e':
- theGPT.JustLooking(0);
- theGPT.MoveSecondHeaderToEnd();
- saveData = 1;
- break;
- case 'E':
- cout << theGPT.FindLastInFree(theGPT.FindFirstInLargest()) << "\n";
- break;
- case 'f':
- cout << theGPT.FindFirstInLargest() << "\n";
- break;
- case 'F':
- temp = theGPT.FindFirstInLargest();
- theGPT.Align(&temp);
- cout << temp << "\n";
- break;
- case 'g':
- theGPT.JustLooking(0);
- saveData = 1;
- saveNonGPT = 1;
- break;
- case 'G':
- theGPT.JustLooking(0);
- saveData = 1;
- theGPT.RandomizeGUIDs();
- break;
- case 'h':
- theGPT.JustLooking(0);
- if (BuildMBR(theGPT, hybrids, 1) == 1)
- saveData = 1;
- break;
- case 'i':
- theGPT.ShowPartDetails(infoPartNum - 1);
- break;
- case 'l':
- if (theGPT.LoadGPTBackup((string) backupFile) == 1) {
- theGPT.JustLooking(0);
- saveData = 1;
- } else {
- saveData = 0;
- neverSaveData = 1;
- cerr << "Error loading backup file!\n";
- } // else
- free(backupFile);
- break;
- case 'L':
- break;
- case 'm':
- theGPT.JustLooking(0);
- if (BuildMBR(theGPT, mbrParts, 0) == 1) {
- if (!pretend) {
- if (theGPT.SaveMBR()) {
- theGPT.DestroyGPT();
- } else
- cerr << "Problem saving MBR!\n";
- } // if
- saveNonGPT = 0;
- pretend = 1; // Not really, but works around problem if -g is used with this...
- saveData = 0;
- } // if
- break;
- case 'n':
- theGPT.JustLooking(0);
- partNum = (int) GetInt(newPartInfo, 1) - 1;
- if (partNum < 0)
- partNum = theGPT.FindFirstFreePart();
- low = theGPT.FindFirstInLargest();
- high = theGPT.FindLastInFree(low);
- startSector = IeeeToInt(GetString(newPartInfo, 2), sSize, low, high, low);
- endSector = IeeeToInt(GetString(newPartInfo, 3), sSize, startSector, high, high);
- if (theGPT.CreatePartition(partNum, startSector, endSector)) {
- saveData = 1;
- } else {
- cerr << "Could not create partition " << partNum + 1 << " from "
- << startSector << " to " << endSector << "\n";
- neverSaveData = 1;
- } // if/else
- free(newPartInfo);
- break;
- case 'N':
- theGPT.JustLooking(0);
- startSector = theGPT.FindFirstInLargest();
- endSector = theGPT.FindLastInFree(startSector);
- if (largestPartNum < 0)
- largestPartNum = theGPT.FindFirstFreePart();
- if (theGPT.CreatePartition(largestPartNum - 1, startSector, endSector)) {
- saveData = 1;
- } else {
- cerr << "Could not create partition " << largestPartNum << " from "
- << startSector << " to " << endSector << "\n";
- neverSaveData = 1;
- } // if/else
- break;
- case 'o':
- theGPT.JustLooking(0);
- theGPT.ClearGPTData();
- saveData = 1;
- break;
- case 'p':
- theGPT.DisplayGPTData();
- break;
- case 'P':
- pretend = 1;
- break;
- case 'r':
- theGPT.JustLooking(0);
- uint64_t p1, p2;
- p1 = GetInt(twoParts, 1) - 1;
- p2 = GetInt(twoParts, 2) - 1;
- if (theGPT.SwapPartitions((uint32_t) p1, (uint32_t) p2) == 0) {
- neverSaveData = 1;
- cerr << "Cannot swap partitions " << p1 + 1 << " and " << p2 + 1 << "\n";
- } else saveData = 1;
- break;
- case 'R':
- secondDevice = theGPT;
- secondDevice.SetDisk(outDevice);
- secondDevice.JustLooking(0);
- secondDevice.SaveGPTData(1);
- break;
- case 's':
- theGPT.JustLooking(0);
- theGPT.SortGPT();
- saveData = 1;
- break;
- case 'S':
- theGPT.JustLooking(0);
- if (theGPT.SetGPTSize(tableSize) == 0)
- neverSaveData = 1;
- else
- saveData = 1;
- break;
- case 't':
- theGPT.JustLooking(0);
- partNum = (int) GetInt(typeCode, 1) - 1;
- typeHelper = GetString(typeCode, 2);
- if ((typeHelper != (GUIDData) "00000000-0000-0000-0000-000000000000") &&
- (theGPT.ChangePartType(partNum, typeHelper))) {
- saveData = 1;
- } else {
- cerr << "Could not change partition " << partNum + 1
- << "'s type code to " << GetString(typeCode, 2) << "!\n";
- neverSaveData = 1;
- } // if/else
- free(typeCode);
- break;
- case 'T':
- theGPT.JustLooking(0);
- theGPT.XFormDisklabel(bsdPartNum - 1);
- saveData = 1;
- break;
- case 'u':
- theGPT.JustLooking(0);
- saveData = 1;
- gptPartNum = (int) GetInt(partGUID, 1) - 1;
- theGPT.SetPartitionGUID(gptPartNum, GetString(partGUID, 2).c_str());
- break;
- case 'U':
- theGPT.JustLooking(0);
- saveData = 1;
- theGPT.SetDiskGUID(diskGUID);
- break;
- case 'v':
- theGPT.Verify();
- break;
- case 'z':
- if (!pretend) {
- theGPT.DestroyGPT();
- } // if
- saveNonGPT = 0;
- saveData = 0;
- break;
- case 'Z':
- if (!pretend) {
- theGPT.DestroyGPT();
- theGPT.DestroyMBR();
- } // if
- saveNonGPT = 0;
- saveData = 0;
- break;
- default:
- cerr << "Unknown option (-" << opt << ")!\n";
- break;
- } // switch
- } // while
- if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend)) {
- theGPT.SaveGPTData(1);
- }
- if (saveData && (!saveNonGPT)) {
- cout << "Non-GPT disk; not saving changes. Use -g to override.\n";
- retval = 3;
- } // if
- if (neverSaveData) {
- cerr << "Error encountered; not saving changes.\n";
- retval = 4;
- } // if
- } else { // if loaded OK
- poptResetContext(poptCon);
- // Do a few types of operations even if there are problems....
- while ((opt = poptGetNextOpt(poptCon)) > 0) {
- switch (opt) {
- case 'v':
- cout << "Verification may miss some problems or report too many!\n";
- theGPT.Verify();
- break;
- case 'z':
- if (!pretend) {
- theGPT.DestroyGPT();
- } // if
- saveNonGPT = 0;
- saveData = 0;
- break;
- case 'Z':
- if (!pretend) {
- theGPT.DestroyGPT();
- theGPT.DestroyMBR();
- } // if
- saveNonGPT = 0;
- saveData = 0;
- break;
- } // switch
- } // while
- retval = 2;
- } // if/else loaded OK
- } // if (device != NULL)
- poptFreeContext(poptCon);
-
- return retval;
+ GPTDataCL theGPT;
+ return theGPT.DoOptions(argc, argv);
} // main
-
-// Create a hybrid or regular MBR from GPT data structures
-int BuildMBR(GPTData & theGPT, char* argument, int isHybrid) {
- int numParts, allOK = 1, i, origPartNum;
- MBRPart newPart;
- BasicMBRData newMBR;
-
- if ((&theGPT != NULL) && (argument != NULL)) {
- numParts = CountColons(argument) + 1;
- if (numParts <= (4 - isHybrid)) {
- newMBR.SetDisk(theGPT.GetDisk());
- for (i = 0; i < numParts; i++) {
- origPartNum = GetInt(argument, i + 1) - 1;
- if (theGPT.IsUsedPartNum(origPartNum)) {
- newPart.SetInclusion(PRIMARY);
- newPart.SetLocation(theGPT[origPartNum].GetFirstLBA(),
- theGPT[origPartNum].GetLengthLBA());
- newPart.SetStatus(0);
- newPart.SetType((uint8_t)(theGPT[origPartNum].GetHexType() / 0x0100));
- newMBR.AddPart(i + isHybrid, newPart);
- } else {
- cerr << "Partition " << origPartNum << " does not exist! Aborting operation!\n";
- allOK = 0;
- } // if/else
- } // for
- if (isHybrid) {
- newPart.SetInclusion(PRIMARY);
- newPart.SetLocation(1, newMBR.FindLastInFree(1));
- newPart.SetStatus(0);
- newPart.SetType(0xEE);
- newMBR.AddPart(0, newPart);
- } // if
- theGPT.SetProtectiveMBR(newMBR);
- } else allOK = 0;
- } else allOK = 0;
- if (!allOK)
- cerr << "Problem creating MBR!\n";
- return allOK;
-} // BuildMBR()
-
-// Returns the number of colons in argument string, ignoring the
-// first character (thus, a leading colon is ignored, as GetString()
-// does).
-int CountColons(char* argument) {
- int num = 0;
-
- while ((argument[0] != '\0') && (argument = strchr(&argument[1], ':')))
- num++;
-
- return num;
-} // CountColons()
-
-// Extract integer data from argument string, which should be colon-delimited
-uint64_t GetInt(const string & argument, int itemNum) {
- uint64_t retval;
-
- istringstream inString(GetString(argument, itemNum));
- inString >> retval;
- return retval;
-} // GetInt()
-
-// Extract string data from argument string, which should be colon-delimited
-// If string begins with a colon, that colon is skipped in the counting. If an
-// invalid itemNum is specified, returns an empty string.
-string GetString(string argument, int itemNum) {
- size_t startPos = 0, endPos = 0;
- string retVal = "";
- int foundLast = 0;
- int numFound = 0;
-
- if (argument[0] == ':')
- argument.erase(0, 1);
- while ((numFound < itemNum) && (!foundLast)) {
- endPos = argument.find(':', startPos);
- numFound++;
- if (endPos == string::npos) {
- foundLast = 1;
- endPos = argument.length();
- } else if (numFound < itemNum) {
- startPos = endPos + 1;
- } // if/elseif
- } // while
- if ((numFound == itemNum) && (numFound > 0))
- retVal = argument.substr(startPos, endPos - startPos);
-
- return retVal;
-} // GetString()
diff --git a/support.cc b/support.cc
index 24bcffb..db5adb2 100644
--- a/support.cc
+++ b/support.cc
@@ -110,7 +110,7 @@ uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize,
// to 2. If value includes a "+", adds low and subtracts 1; if SIValue
// inclues a "-", subtracts from high. If IeeeValue is empty, returns def.
// Returns final sector value. In case inValue is invalid, returns 0 (a
-// sector value that's always is use on GPT and therefore invalid); and if
+// sector value that's always in use on GPT and therefore invalid); and if
// inValue works out to something outside the range low-high, returns the
// computed value; the calling function is responsible for checking the
// validity of this value.
@@ -304,3 +304,19 @@ void ReverseBytes(void* theValue, int numBytes) {
exit(1);
} // if/else
} // ReverseBytes()
+
+// On Windows, display a warning and ask whether to continue. If the user elects
+// not to continue, exit immediately.
+void WinWarning(void) {
+ #ifdef _WIN32
+ cout << "\a************************************************************************\n"
+ << "Most versions of Windows cannot boot from a GPT disk, and most varieties\n"
+ << "prior to Vista cannot read GPT disks. Therefore, you should exit now\n"
+ << "unless you understand the implications of converting MBR to GPT or creating\n"
+ << "a new GPT disk layout!\n"
+ << "************************************************************************\n\n";
+ cout << "Are you SURE you want to continue? ";
+ if (GetYN() != 'Y')
+ exit(0);
+ #endif
+} // WinWarning()
diff --git a/support.h b/support.h
index edae3dd..998c5b4 100644
--- a/support.h
+++ b/support.h
@@ -8,7 +8,7 @@
#ifndef __GPTSUPPORT
#define __GPTSUPPORT
-#define GPTFDISK_VERSION "0.7.2"
+#define GPTFDISK_VERSION "0.8.0"
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
// Darwin (Mac OS) & FreeBSD: disk IOCTLs are different, and there is no lseek64
@@ -72,10 +72,11 @@ int GetNumber(int low, int high, int def, const string & prompt);
char GetYN(void);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
uint64_t IeeeToInt(string IeeeValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def = 0);
-string BytesToIeee(uint64_t size, uint32_t sectorSize = 1);
+string BytesToIeee(uint64_t size, uint32_t sectorSize);
unsigned char StrToHex(const string & input, unsigned int position);
int IsHex(string input); // Returns 1 if input can be hexadecimal number....
int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian
void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
+void WinWarning(void);
#endif