Changes for version 0.8.0
This commit is contained in:
15
Makefile
15
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
12
Makefile.mac
12
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
|
||||
|
||||
33
NEWS
33
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):
|
||||
------------------
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
23
current.spec
23
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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
2
diskio.h
2
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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
29
gdisk.8
29
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,
|
||||
|
||||
389
gdisk.cc
389
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
|
||||
@@ -74,373 +59,3 @@ int main(int argc, char* argv[]) {
|
||||
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()
|
||||
|
||||
33
gpt.cc
33
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);
|
||||
} // if/else
|
||||
delete[] storage;
|
||||
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
|
||||
return newCrcOk;
|
||||
} // if/else
|
||||
delete[] partsToCheck;
|
||||
} // if
|
||||
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);
|
||||
|
||||
370
gpttext.cc
370
gpttext.cc
@@ -33,7 +33,7 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*******************************************
|
||||
/********************************************
|
||||
* *
|
||||
* GPTDataText class and related structures *
|
||||
* *
|
||||
@@ -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. *
|
||||
|
||||
12
gpttext.h
12
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);
|
||||
|
||||
24
mbrpart.cc
24
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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
40
sgdisk.8
40
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
|
||||
@@ -546,10 +561,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 systems, particularly with
|
||||
the more obscure features of the program.
|
||||
|
||||
.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,
|
||||
|
||||
506
sgdisk.cc
506
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()
|
||||
|
||||
18
support.cc
18
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()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user