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)
|
LIB_HEADERS=$(LIB_NAMES:=.h)
|
||||||
DEPEND= makedepend $(CXXFLAGS)
|
DEPEND= makedepend $(CXXFLAGS)
|
||||||
|
|
||||||
all: gdisk sgdisk fixparts
|
all: cgdisk gdisk sgdisk fixparts
|
||||||
|
|
||||||
gdisk: $(LIB_OBJS) gdisk.o gpttext.o
|
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) -luuid -o gdisk
|
||||||
$(CXX) $(LIB_OBJS) gdisk.o gpttext.o $(LDFLAGS) -licuio -licuuc -luuid -o gdisk
|
$(CXX) $(LIB_OBJS) gdisk.o gpttext.o $(LDFLAGS) -licuio -licuuc -luuid -o gdisk
|
||||||
|
|
||||||
sgdisk: $(LIB_OBJS) sgdisk.o
|
cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o
|
||||||
# $(CXX) $(LIB_OBJS) sgdisk.o $(LDFLAGS) -luuid -lpopt -o sgdisk
|
# $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -luuid -lncurses -o cgdisk
|
||||||
$(CXX) $(LIB_OBJS) sgdisk.o $(LDFLAGS) -licuio -licuuc -luuid -lpopt -o sgdisk
|
$(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
|
fixparts: $(MBR_LIB_OBJS) fixparts.o
|
||||||
$(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -o fixparts
|
$(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -o fixparts
|
||||||
@@ -28,7 +32,7 @@ lint: #no pre-reqs
|
|||||||
lint $(SRCS)
|
lint $(SRCS)
|
||||||
|
|
||||||
clean: #no pre-reqs
|
clean: #no pre-reqs
|
||||||
rm -f core *.o *~ gdisk sgdisk fixparts
|
rm -f core *.o *~ gdisk sgdisk cgdisk fixparts
|
||||||
|
|
||||||
# what are the source dependencies
|
# what are the source dependencies
|
||||||
depend: $(SRCS)
|
depend: $(SRCS)
|
||||||
@@ -38,3 +42,4 @@ $(OBJS):
|
|||||||
$(CRITICAL_CXX_FLAGS)
|
$(CRITICAL_CXX_FLAGS)
|
||||||
|
|
||||||
# DO NOT DELETE
|
# DO NOT DELETE
|
||||||
|
|
||||||
|
|||||||
@@ -11,15 +11,19 @@ MBR_LIB_OBJS=$(MBR_LIBS:=.o)
|
|||||||
LIB_HEADERS=$(LIB_NAMES:=.h)
|
LIB_HEADERS=$(LIB_NAMES:=.h)
|
||||||
DEPEND= makedepend $(CXXFLAGS)
|
DEPEND= makedepend $(CXXFLAGS)
|
||||||
|
|
||||||
all: gdisk sgdisk fixparts
|
all: gdisk cgdisk sgdisk fixparts
|
||||||
|
|
||||||
gdisk: $(LIB_OBJS) gdisk.o gpttext.o
|
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) -licuio -luuid -o gdisk
|
||||||
# $(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/usr/local/lib $(LDFLAGS) -luuid -o gdisk
|
# $(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/usr/local/lib $(LDFLAGS) -luuid -o gdisk
|
||||||
|
|
||||||
sgdisk: $(LIB_OBJS) sgdisk.o
|
cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o
|
||||||
$(CXX) $(LIB_OBJS) sgdisk.o -L/usr/local/lib $(LDFLAGS) -luuid -licuio -lpopt -o sgdisk
|
$(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o -L/usr/local/lib $(LDFLAGS) -licuio -luuid -lncurses -o cgdisk
|
||||||
# $(CXX) $(LIB_OBJS) sgdisk.o -L/usr/local/lib $(LDFLAGS) -luuid -lpopt -o sgdisk
|
# $(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
|
fixparts: $(MBR_LIB_OBJS) fixparts.o
|
||||||
$(CXX) $(MBR_LIB_OBJS) fixparts.o -L/usr/local/lib $(LDFLAGS) -o fixparts
|
$(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)
|
LIB_HEADERS=$(LIB_NAMES:=.h)
|
||||||
DEPEND= makedepend $(CFLAGS)
|
DEPEND= makedepend $(CFLAGS)
|
||||||
|
|
||||||
all: gdisk sgdisk fixparts
|
all: gdisk sgdisk cgdisk fixparts
|
||||||
|
|
||||||
gdisk: $(LIB_OBJS) gpttext.o gdisk.o
|
gdisk: $(LIB_OBJS) gpttext.o gdisk.o
|
||||||
# $(CXX) $(LIB_OBJS) gpttext.o gdisk.o -o gdisk
|
# $(CXX) $(LIB_OBJS) gpttext.o gdisk.o -o gdisk
|
||||||
$(CXX) $(LIB_OBJS) -L/usr/lib -licucore gpttext.o gdisk.o -o gdisk
|
$(CXX) $(LIB_OBJS) -L/usr/lib -licucore gpttext.o gdisk.o -o gdisk
|
||||||
|
|
||||||
sgdisk: $(LIB_OBJS) sgdisk.o
|
cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o
|
||||||
# $(CXX) $(LIB_OBJS) sgdisk.o -L/sw/lib -lpopt -o sgdisk
|
# $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -lncurses -o sgdisk
|
||||||
$(CXX) $(LIB_OBJS) sgdisk.o -L/sw/lib -licucore -lpopt -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
|
fixparts: $(MBR_LIB_OBJS) fixparts.o
|
||||||
$(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -o fixparts
|
$(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):
|
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
|
// the most common value for big disks (255 heads, 63 sectors per
|
||||||
// track, & however many cylinders that computes to).
|
// track, & however many cylinders that computes to).
|
||||||
void BasicMBRData::ReadCHSGeom(void) {
|
void BasicMBRData::ReadCHSGeom(void) {
|
||||||
|
int err;
|
||||||
|
|
||||||
numHeads = myDisk->GetNumHeads();
|
numHeads = myDisk->GetNumHeads();
|
||||||
numSecspTrack = myDisk->GetNumSecsPerTrack();
|
numSecspTrack = myDisk->GetNumSecsPerTrack();
|
||||||
|
diskSize = myDisk->DiskSize(&err);
|
||||||
|
blockSize = myDisk->GetBlockSize();
|
||||||
partitions[0].SetGeometry(numHeads, numSecspTrack, diskSize, blockSize);
|
partitions[0].SetGeometry(numHeads, numSecspTrack, diskSize, blockSize);
|
||||||
} // BasicMBRData::ReadCHSGeom()
|
} // BasicMBRData::ReadCHSGeom()
|
||||||
|
|
||||||
|
|||||||
23
current.spec
23
current.spec
@@ -1,21 +1,20 @@
|
|||||||
Summary: GPT partitioning and MBR repair software
|
Summary: GPT partitioning and MBR repair software
|
||||||
Name: gptfdisk
|
Name: gptfdisk
|
||||||
Version: 0.7.2
|
Version: 0.8.0
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
License: GPLv2
|
License: GPLv2
|
||||||
URL: http://www.rodsbooks.com/gdisk
|
URL: http://www.rodsbooks.com/gdisk
|
||||||
Group: Applications/System
|
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)
|
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
|
||||||
|
|
||||||
%description
|
%description
|
||||||
|
|
||||||
Partitioning software for GPT disks and to repair MBR
|
Partitioning software for GPT disks and to repair MBR disks. The gdisk,
|
||||||
disks. The gdisk and sgdisk utilities (in the gdisk
|
cgdisk, and sgdisk utilities (in the gdisk package) are GPT-enabled
|
||||||
package) are GPT-enabled partitioning tools; the
|
partitioning tools; the fixparts utility (in the fixparts package) fixes
|
||||||
fixparts utility (in the fixparts package) fixes some
|
some problems with MBR disks that can be created by buggy partitioning
|
||||||
problems with MBR disks that can be created by buggy
|
software.
|
||||||
partitioning software.
|
|
||||||
|
|
||||||
%package -n gdisk
|
%package -n gdisk
|
||||||
|
|
||||||
@@ -41,9 +40,11 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
mkdir -p $RPM_BUILD_ROOT/usr/sbin
|
mkdir -p $RPM_BUILD_ROOT/usr/sbin
|
||||||
install -Dp -m0755 gdisk $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 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 -m0755 fixparts $RPM_BUILD_ROOT/usr/sbin
|
||||||
install -Dp -m0644 gdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/gdisk.8
|
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 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
|
install -Dp -m0644 fixparts.8 $RPM_BUILD_ROOT/%{_mandir}/man8/fixparts.8
|
||||||
|
|
||||||
%clean
|
%clean
|
||||||
@@ -54,8 +55,10 @@ rm -rf $RPM_BUILD_ROOT
|
|||||||
%doc NEWS COPYING README
|
%doc NEWS COPYING README
|
||||||
/usr/sbin/gdisk
|
/usr/sbin/gdisk
|
||||||
/usr/sbin/sgdisk
|
/usr/sbin/sgdisk
|
||||||
|
/usr/sbin/cgdisk
|
||||||
%doc %{_mandir}/man8/gdisk.8*
|
%doc %{_mandir}/man8/gdisk.8*
|
||||||
%doc %{_mandir}/man8/sgdisk.8*
|
%doc %{_mandir}/man8/sgdisk.8*
|
||||||
|
%doc %{_mandir}/man8/cgdisk.8*
|
||||||
|
|
||||||
%package -n fixparts
|
%package -n fixparts
|
||||||
|
|
||||||
@@ -77,5 +80,5 @@ provides a few additional partition manipulation features.
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Sun Jun 26 2011 R Smith <rodsmith@rodsbooks.com> - 0.7.2
|
* Sat Sep 10 2011 R Smith <rodsmith@rodsbooks.com> - 0.8.0
|
||||||
- Created spec file for 0.7.2 release
|
- 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
|
// Resync disk caches so the OS uses the new partition table. This code varies
|
||||||
// a lot from one OS to another.
|
// 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 i, platformFound = 0;
|
// (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 disk isn't open, try to open it....
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
@@ -233,9 +236,12 @@ void DiskIO::DiskSync(void) {
|
|||||||
sleep(1); // Theoretically unnecessary, but ioctl() fails sometimes if omitted....
|
sleep(1); // Theoretically unnecessary, but ioctl() fails sometimes if omitted....
|
||||||
fsync(fd);
|
fsync(fd);
|
||||||
i = ioctl(fd, BLKRRPART);
|
i = ioctl(fd, BLKRRPART);
|
||||||
if (i)
|
if (i) {
|
||||||
cout << "Warning: The kernel is still using the old partition table.\n"
|
cout << "Warning: The kernel is still using the old partition table.\n"
|
||||||
<< "The new table will be used at the next reboot.\n";
|
<< "The new table will be used at the next reboot.\n";
|
||||||
|
} else {
|
||||||
|
retval = 1;
|
||||||
|
} // if/else
|
||||||
platformFound++;
|
platformFound++;
|
||||||
#endif
|
#endif
|
||||||
if (platformFound == 0)
|
if (platformFound == 0)
|
||||||
@@ -243,6 +249,7 @@ void DiskIO::DiskSync(void) {
|
|||||||
if (platformFound > 1)
|
if (platformFound > 1)
|
||||||
cerr << "\nWarning: We seem to be running on multiple platforms!\n";
|
cerr << "\nWarning: We seem to be running on multiple platforms!\n";
|
||||||
} // if (isOpen)
|
} // if (isOpen)
|
||||||
|
return retval;
|
||||||
} // DiskIO::DiskSync()
|
} // DiskIO::DiskSync()
|
||||||
|
|
||||||
// Seek to the specified sector. Returns 1 on success, 0 on failure.
|
// 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
|
// Resync disk caches so the OS uses the new partition table. This code varies
|
||||||
// a lot from one OS to another.
|
// 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;
|
DWORD i;
|
||||||
GET_LENGTH_INFORMATION buf;
|
GET_LENGTH_INFORMATION buf;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
// If disk isn't open, try to open it....
|
// If disk isn't open, try to open it....
|
||||||
if (!openForWrite) {
|
if (!openForWrite) {
|
||||||
@@ -174,12 +176,14 @@ void DiskIO::DiskSync(void) {
|
|||||||
} else {
|
} else {
|
||||||
cout << "Disk synchronization succeeded! The computer should now use the new\n"
|
cout << "Disk synchronization succeeded! The computer should now use the new\n"
|
||||||
<< "partition table.\n";
|
<< "partition table.\n";
|
||||||
|
retval = 1;
|
||||||
} // if/else
|
} // if/else
|
||||||
} else {
|
} else {
|
||||||
cout << "Unable to open the disk for synchronization operation! The computer will\n"
|
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"
|
<< "continue to use the old partition table until you reboot or remove and\n"
|
||||||
<< "re-insert the disk!\n";
|
<< "re-insert the disk!\n";
|
||||||
} // if (isOpen)
|
} // if (isOpen)
|
||||||
|
return retval;
|
||||||
} // DiskIO::DiskSync()
|
} // DiskIO::DiskSync()
|
||||||
|
|
||||||
// Seek to the specified sector. Returns 1 on success, 0 on failure.
|
// 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 Seek(uint64_t sector);
|
||||||
int Read(void* buffer, int numBytes);
|
int Read(void* buffer, int numBytes);
|
||||||
int Write(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);
|
int GetBlockSize(void);
|
||||||
uint32_t GetNumHeads(void);
|
uint32_t GetNumHeads(void);
|
||||||
uint32_t GetNumSecsPerTrack(void);
|
uint32_t GetNumSecsPerTrack(void);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
|
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||||
.\" May be distributed under the GNU General Public License
|
.\" May be distributed under the GNU General Public License
|
||||||
.TH "FIXPARTS" "8" "0.7.2" "Roderick W. Smith" "FixParts Manual"
|
.TH "FIXPARTS" "8" "0.8.0" "Roderick W. Smith" "FixParts Manual"
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
fixparts \- MBR partition table repair utility
|
fixparts \- MBR partition table repair utility
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
@@ -202,7 +202,7 @@ see a summary of available options.
|
|||||||
.PP
|
.PP
|
||||||
|
|
||||||
.SH "BUGS"
|
.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:
|
should be considered beta software. Known bugs and limitations include:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@@ -266,6 +266,7 @@ Contributors:
|
|||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
\fBcfdisk (8)\fR,
|
\fBcfdisk (8)\fR,
|
||||||
|
\fBcgdisk (8)\fR,
|
||||||
\fBfdisk (8)\fR,
|
\fBfdisk (8)\fR,
|
||||||
\fBmkfs (8)\fR,
|
\fBmkfs (8)\fR,
|
||||||
\fBparted (8)\fR,
|
\fBparted (8)\fR,
|
||||||
|
|||||||
29
gdisk.8
29
gdisk.8
@@ -1,6 +1,6 @@
|
|||||||
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
|
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||||
.\" May be distributed under the GNU General Public License
|
.\" May be distributed under the GNU General Public License
|
||||||
.TH "GDISK" "8" "0.7.2" "Roderick W. Smith" "GPT fdisk Manual"
|
.TH "GDISK" "8" "0.8.0" "Roderick W. Smith" "GPT fdisk Manual"
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
gdisk \- Interactive GUID partition table (GPT) manipulator
|
gdisk \- Interactive GUID partition table (GPT) manipulator
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
@@ -93,7 +93,7 @@ and in whatever sizes are desired.
|
|||||||
.B *
|
.B *
|
||||||
Boot disks for EFI\-based systems require an \fIEFI System
|
Boot disks for EFI\-based systems require an \fIEFI System
|
||||||
Partition\fR (\fBgdisk\fR internal code 0xEF00) formatted as FAT\-32.
|
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
|
Boot\-related files are stored here. (Note that GNU Parted identifies
|
||||||
such partitions as having the "boot flag" set.)
|
such partitions as having the "boot flag" set.)
|
||||||
|
|
||||||
@@ -467,15 +467,15 @@ option on the main menu.
|
|||||||
.TP
|
.TP
|
||||||
.B l
|
.B l
|
||||||
Change the sector alignment value. Disks with more logical sectors per
|
Change the sector alignment value. Disks with more logical sectors per
|
||||||
physical sectors (such as some Western Digital models introduced in
|
physical sectors (such as modern Advanced Format drives), some RAID
|
||||||
December of 2009) and some RAID configurations can suffer performance
|
configurations, and many SSD devices, can suffer performance problems if
|
||||||
problems if partitions are not aligned properly for their internal data
|
partitions are not aligned properly for their internal data structures. On
|
||||||
structures. On new disks, GPT fdisk attempts to align partitions on
|
new disks, GPT fdisk attempts to align partitions on 2048\-sector (1MiB)
|
||||||
2048\-sector (1MiB) boundaries by default, which optimizes performance for
|
boundaries by default, which optimizes performance for all of these disk
|
||||||
both of these disk types. On pre\-partitioned disks, GPT fdisk attempts to
|
types. On pre\-partitioned disks, GPT fdisk attempts to identify the
|
||||||
identify the alignment value used on that disk, but will set 8-sector
|
alignment value used on that disk, but will set 8-sector alignment on disks
|
||||||
alignment on disks larger than 300 GB even if lesser alignment values are
|
larger than 300 GB even if lesser alignment values are detected. In either
|
||||||
detected. In either case, it can be changed by using this option.
|
case, it can be changed by using this option.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B m
|
.B m
|
||||||
@@ -561,7 +561,7 @@ entering data. When only one option is possible, \fBgdisk\fR
|
|||||||
usually bypasses the prompt entirely.
|
usually bypasses the prompt entirely.
|
||||||
|
|
||||||
.SH "BUGS"
|
.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:
|
should be considered beta software. Known bugs and limitations include:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@@ -649,10 +649,6 @@ options in this case.
|
|||||||
|
|
||||||
.PP
|
.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"
|
.SH "AUTHORS"
|
||||||
Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
|
Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||||
|
|
||||||
@@ -671,6 +667,7 @@ Contributors:
|
|||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
\fBcfdisk (8)\fR,
|
\fBcfdisk (8)\fR,
|
||||||
|
\fBcgdisk (8)\fR,
|
||||||
\fBfdisk (8)\fR,
|
\fBfdisk (8)\fR,
|
||||||
\fBmkfs (8)\fR,
|
\fBmkfs (8)\fR,
|
||||||
\fBparted (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
|
/* 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. */
|
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
|
||||||
#include <locale>
|
|
||||||
#include "mbr.h"
|
|
||||||
#include "gpttext.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[]) {
|
int main(int argc, char* argv[]) {
|
||||||
GPTDataTextUI theGPT;
|
GPTDataTextUI theGPT;
|
||||||
@@ -45,14 +30,14 @@ int main(int argc, char* argv[]) {
|
|||||||
else if (theGPT.LoadPartitions(device)) {
|
else if (theGPT.LoadPartitions(device)) {
|
||||||
if (theGPT.GetState() != use_gpt)
|
if (theGPT.GetState() != use_gpt)
|
||||||
WinWarning();
|
WinWarning();
|
||||||
MainMenu(device, &theGPT);
|
theGPT.MainMenu(device);
|
||||||
} // if/elseif
|
} // if/elseif
|
||||||
break;
|
break;
|
||||||
case 2: // basic usage
|
case 2: // basic usage
|
||||||
if (theGPT.LoadPartitions(argv[1])) {
|
if (theGPT.LoadPartitions(argv[1])) {
|
||||||
if (theGPT.GetState() != use_gpt)
|
if (theGPT.GetState() != use_gpt)
|
||||||
WinWarning();
|
WinWarning();
|
||||||
MainMenu(argv[1], &theGPT);
|
theGPT.MainMenu(argv[1]);
|
||||||
} // if
|
} // if
|
||||||
break;
|
break;
|
||||||
case 3: // usage with "-l" option
|
case 3: // usage with "-l" option
|
||||||
@@ -74,373 +59,3 @@ int main(int argc, char* argv[]) {
|
|||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
} // main
|
} // 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
|
// Check the partition table pointed to by header, but don't keep it
|
||||||
// around.
|
// 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) {
|
int GPTData::CheckTable(struct GPTHeader *header) {
|
||||||
uint32_t sizeOfParts, newCRC;
|
uint32_t sizeOfParts, newCRC;
|
||||||
uint8_t *storage;
|
GPTPart *partsToCheck;
|
||||||
int newCrcOk = 0;
|
int allOK = 0;
|
||||||
|
|
||||||
// Load partition table into temporary storage to check
|
// Load partition table into temporary storage to check
|
||||||
// its CRC and store the results, then discard this temporary
|
// its CRC and store the results, then discard this temporary
|
||||||
// storage, since we don't use it in any but recovery operations
|
// storage, since we don't use it in any but recovery operations
|
||||||
if (myDisk.Seek(header->partitionEntriesLBA)) {
|
if (myDisk.Seek(header->partitionEntriesLBA)) {
|
||||||
|
partsToCheck = new GPTPart[header->numParts];
|
||||||
sizeOfParts = header->numParts * header->sizeOfPartitionEntries;
|
sizeOfParts = header->numParts * header->sizeOfPartitionEntries;
|
||||||
storage = new uint8_t[sizeOfParts];
|
if (partsToCheck == NULL) {
|
||||||
if (storage == NULL) {
|
|
||||||
cerr << "Could not allocate memory in GPTData::CheckTable()! Terminating!\n";
|
cerr << "Could not allocate memory in GPTData::CheckTable()! Terminating!\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
} // if
|
} // 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";
|
cerr << "Warning! Error " << errno << " reading partition table for CRC check!\n";
|
||||||
} else {
|
} else {
|
||||||
newCRC = chksum_crc32((unsigned char*) storage, sizeOfParts);
|
newCRC = chksum_crc32((unsigned char*) partsToCheck, sizeOfParts);
|
||||||
newCrcOk = (newCRC == header->partitionEntriesCRC);
|
allOK = (newCRC == header->partitionEntriesCRC);
|
||||||
} // if/else
|
if (memcmp(partitions, partsToCheck, sizeOfParts) != 0) {
|
||||||
delete[] storage;
|
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
|
||||||
return newCrcOk;
|
} // if/else
|
||||||
|
delete[] partsToCheck;
|
||||||
|
} // if
|
||||||
|
return allOK;
|
||||||
} // GPTData::CheckTable()
|
} // GPTData::CheckTable()
|
||||||
|
|
||||||
// Writes GPT (and protective MBR) to disk. If quiet==1,
|
// Writes GPT (and protective MBR) to disk. If quiet==1,
|
||||||
// Returns 1 on successful
|
// Returns 1 on successful write, 0 if there was a problem.
|
||||||
// write, 0 if there was a problem.
|
|
||||||
int GPTData::SaveGPTData(int quiet) {
|
int GPTData::SaveGPTData(int quiet) {
|
||||||
int allOK = 1, littleEndian;
|
int allOK = 1, littleEndian;
|
||||||
char answer;
|
char answer;
|
||||||
@@ -1227,7 +1232,7 @@ int GPTData::DestroyGPT(void) {
|
|||||||
tableSize = numParts * mainHeader.sizeOfPartitionEntries;
|
tableSize = numParts * mainHeader.sizeOfPartitionEntries;
|
||||||
emptyTable = new uint8_t[tableSize];
|
emptyTable = new uint8_t[tableSize];
|
||||||
if (emptyTable == NULL) {
|
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);
|
exit(1);
|
||||||
} // if
|
} // if
|
||||||
memset(emptyTable, 0, tableSize);
|
memset(emptyTable, 0, tableSize);
|
||||||
|
|||||||
370
gpttext.cc
370
gpttext.cc
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
/*******************************************
|
/********************************************
|
||||||
* *
|
* *
|
||||||
* GPTDataText class and related structures *
|
* 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 GPTDataTextUI::GetPartNum(void) {
|
||||||
uint32_t partNum;
|
uint32_t partNum;
|
||||||
uint32_t low, high;
|
uint32_t low, high;
|
||||||
@@ -257,7 +258,6 @@ void GPTDataTextUI::DeletePartition(void) {
|
|||||||
} // GPTDataTextUI::DeletePartition()
|
} // GPTDataTextUI::DeletePartition()
|
||||||
|
|
||||||
// Prompt user for a partition number, then change its type code
|
// Prompt user for a partition number, then change its type code
|
||||||
// using ChangeGPTType(struct GPTPartition*) function.
|
|
||||||
void GPTDataTextUI::ChangePartType(void) {
|
void GPTDataTextUI::ChangePartType(void) {
|
||||||
int partNum;
|
int partNum;
|
||||||
uint32_t low, high;
|
uint32_t low, high;
|
||||||
@@ -494,6 +494,370 @@ int GPTDataTextUI::XFormToMBR(void) {
|
|||||||
return protectiveMBR.DoMenu();
|
return protectiveMBR.DoMenu();
|
||||||
} // GPTDataTextUI::XFormToMBR()
|
} // 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. *
|
* 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
|
Copyright (C) 2010-2011 Roderick W. Smith
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
@@ -33,7 +33,7 @@ class GPTDataTextUI : public GPTData {
|
|||||||
~GPTDataTextUI(void);
|
~GPTDataTextUI(void);
|
||||||
|
|
||||||
// This one needs to be explicitly defined, even though it does nothing new....
|
// 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
|
// Extended (interactive) versions of some base-class functions
|
||||||
WhichToUse UseWhichPartitions(void);
|
WhichToUse UseWhichPartitions(void);
|
||||||
@@ -53,6 +53,14 @@ class GPTDataTextUI : public GPTData {
|
|||||||
void ShowDetails(void);
|
void ShowDetails(void);
|
||||||
void MakeHybrid(void);
|
void MakeHybrid(void);
|
||||||
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
|
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
|
}; // class GPTDataTextUI
|
||||||
|
|
||||||
int GetMBRTypeCode(int defType);
|
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,
|
void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t ds, uint32_t bs) {
|
||||||
uint32_t blockSize) {
|
|
||||||
numHeads = heads;
|
numHeads = heads;
|
||||||
numSecspTrack = sectors;
|
numSecspTrack = sectors;
|
||||||
|
diskSize = ds;
|
||||||
|
blockSize = bs;
|
||||||
} // MBRPart::SetGeometry
|
} // MBRPart::SetGeometry
|
||||||
|
|
||||||
// Empty the partition (zero out all values).
|
// 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, sets them directly, and sets the CHS values based on the LBA
|
||||||
// values and the current geometry settings.
|
// values and the current geometry settings.
|
||||||
void MBRPart::SetLocation(uint64_t start, uint64_t length) {
|
void MBRPart::SetLocation(uint64_t start, uint64_t length) {
|
||||||
|
int validCHS;
|
||||||
|
|
||||||
if ((start > UINT32_MAX) || (length > UINT32_MAX)) {
|
if ((start > UINT32_MAX) || (length > UINT32_MAX)) {
|
||||||
cerr << "Partition values out of range in MBRPart::SetLocation()!\n"
|
cerr << "Partition values out of range in MBRPart::SetLocation()!\n"
|
||||||
<< "Continuing, but strange problems are now likely!\n";
|
<< "Continuing, but strange problems are now likely!\n";
|
||||||
} // if
|
} // if
|
||||||
firstLBA = (uint32_t) start;
|
firstLBA = (uint32_t) start;
|
||||||
lengthLBA = (uint32_t) length;
|
lengthLBA = (uint32_t) length;
|
||||||
RecomputeCHS();
|
validCHS = RecomputeCHS();
|
||||||
|
|
||||||
// If this is a complete 0xEE protective MBR partition, max out its
|
// If this is a complete 0xEE protective MBR partition, max out its
|
||||||
// CHS last sector value, as per the GPT spec. (Set to 0xffffff,
|
// CHS last sector value, as per the GPT spec. (Set to 0xffffff,
|
||||||
// although the maximum legal MBR value is 0xfeffff, which is
|
// although the maximum legal MBR value is 0xfeffff, which is
|
||||||
// actually what GNU Parted and Apple's Disk Utility use, in
|
// actually what GNU Parted and Apple's Disk Utility use, in
|
||||||
// violation of the GPT spec.)
|
// 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;
|
lastSector[0] = lastSector[1] = lastSector[2] = 0xFF;
|
||||||
} // if
|
} // if
|
||||||
} // MBRPart::SetLocation()
|
} // 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) {
|
if (lengthLBA > 0) {
|
||||||
LBAtoCHS(firstLBA, firstSector);
|
retval = LBAtoCHS(firstLBA, firstSector);
|
||||||
LBAtoCHS(firstLBA + lengthLBA - 1, lastSector);
|
retval *= LBAtoCHS(firstLBA + lengthLBA - 1, lastSector);
|
||||||
} // if
|
} // if
|
||||||
|
return retval;
|
||||||
} // MBRPart::RecomputeCHS()
|
} // MBRPart::RecomputeCHS()
|
||||||
|
|
||||||
// Converts 32-bit LBA value to MBR-style CHS value. Returns 1 if conversion
|
// 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;
|
bool operator<(const MBRPart &other) const;
|
||||||
|
|
||||||
// Set information on partitions or disks...
|
// 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 Empty(void);
|
||||||
void SetStartLBA(uint64_t s);
|
void SetStartLBA(uint64_t s);
|
||||||
void SetLengthLBA(uint64_t l);
|
void SetLengthLBA(uint64_t l);
|
||||||
@@ -101,7 +101,7 @@ public:
|
|||||||
int DoTheyOverlap (const MBRPart& other);
|
int DoTheyOverlap (const MBRPart& other);
|
||||||
|
|
||||||
// Adjust information on partitions or disks...
|
// Adjust information on partitions or disks...
|
||||||
void RecomputeCHS(void);
|
int RecomputeCHS(void);
|
||||||
int LBAtoCHS(uint32_t lba, uint8_t * chs);
|
int LBAtoCHS(uint32_t lba, uint8_t * chs);
|
||||||
void ReverseByteOrder(void);
|
void ReverseByteOrder(void);
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ void PartType::AddAllTypes(void) {
|
|||||||
// Linux-specific partition types....
|
// Linux-specific partition types....
|
||||||
AddType(0x8200, "0657FD6D-A4AB-43C4-84E5-0933C84B4F4F", "Linux swap"); // Linux swap (or Solaris)
|
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, "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(0x8301, "8DA63339-0007-60C0-C436-083AC8230908", "Linux reserved");
|
||||||
AddType(0x8e00, "E6D6D379-F507-44C2-A23C-238F2A3DF928", "Linux LVM");
|
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(0xaf02, "52414944-5F4F-11AA-AA11-00306543ECAC", "Apple RAID offline");
|
||||||
AddType(0xaf03, "4C616265-6C00-11AA-AA11-00306543ECAC", "Apple label");
|
AddType(0xaf03, "4C616265-6C00-11AA-AA11-00306543ECAC", "Apple label");
|
||||||
AddType(0xaf04, "5265636F-7665-11AA-AA11-00306543ECAC", "AppleTV recovery");
|
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)
|
// Solaris partition types (one of which is shared with MacOS)
|
||||||
AddType(0xbe00, "6A82CB45-1DD2-11B2-99A6-080020736631", "Solaris boot");
|
AddType(0xbe00, "6A82CB45-1DD2-11B2-99A6-080020736631", "Solaris boot");
|
||||||
@@ -214,7 +214,7 @@ PartType & PartType::operator=(const string & orig) {
|
|||||||
if (IsHex(orig)) {
|
if (IsHex(orig)) {
|
||||||
sscanf(orig.c_str(), "%x", &hexCode);
|
sscanf(orig.c_str(), "%x", &hexCode);
|
||||||
*this = hexCode;
|
*this = hexCode;
|
||||||
} // if
|
}
|
||||||
} else {
|
} else {
|
||||||
GUIDData::operator=(orig);
|
GUIDData::operator=(orig);
|
||||||
} // if/else hexCode or GUID
|
} // if/else hexCode or GUID
|
||||||
|
|||||||
40
sgdisk.8
40
sgdisk.8
@@ -1,6 +1,6 @@
|
|||||||
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
|
.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||||
.\" May be distributed under the GNU General Public License
|
.\" May be distributed under the GNU General Public License
|
||||||
.TH "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"
|
.SH "NAME"
|
||||||
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
|
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
|
||||||
.SH "SYNOPSIS"
|
.SH "SYNOPSIS"
|
||||||
@@ -89,7 +89,7 @@ and in whatever sizes are desired.
|
|||||||
.B *
|
.B *
|
||||||
Boot disks for EFI\-based systems require an \fIEFI System
|
Boot disks for EFI\-based systems require an \fIEFI System
|
||||||
Partition\fR (\fBsgdisk\fR internal code 0xEF00) formatted as FAT\-32.
|
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
|
Boot\-related files are stored here. (Note that GNU Parted identifies
|
||||||
such partitions as having the "boot flag" set.)
|
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
|
to sectors that are multiples of this value, which defaults to 2048 on
|
||||||
freshly formatted disks. This alignment value is necessary to obtain optimum
|
freshly formatted disks. This alignment value is necessary to obtain optimum
|
||||||
performance with Western Digital Advanced Format and similar drives with larger
|
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
|
.TP
|
||||||
.B \-A, \-\-attributes=list|[partnum:show|or|nand|xor|=|set|clear|toggle|get[:bitnum|hexbitmask]]
|
.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
|
.B \-l, \-\-load\-backup=file
|
||||||
Load partition data from a backup file. This option is the reverse of the
|
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
|
\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
|
.TP
|
||||||
.B \-L, \-\-list\-types
|
.B \-L, \-\-list\-types
|
||||||
@@ -340,8 +343,13 @@ use the first available partition number.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B \-o, \-\-clear
|
.B \-o, \-\-clear
|
||||||
Clear out all partition data. This includes GPT header data,
|
Clear out all partition data. This includes GPT header data, all partition
|
||||||
all partition definitions, and the protective MBR.
|
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
|
.TP
|
||||||
.B \-p, \-\-print
|
.B \-p, \-\-print
|
||||||
@@ -415,9 +423,11 @@ Print a brief summary of available options.
|
|||||||
.B \-v, \-\-verify
|
.B \-v, \-\-verify
|
||||||
Verify disk. This option checks for a variety of problems, such as
|
Verify disk. This option checks for a variety of problems, such as
|
||||||
incorrect CRCs and mismatched main and backup data. This option does not
|
incorrect CRCs and mismatched main and backup data. This option does not
|
||||||
automatically correct most problems, though; for that, you must use
|
automatically correct most problems, though; for that, you must use options
|
||||||
options on the recovery & transformation menu. If no problems are found,
|
on the recovery & transformation menu. If no problems are found, this
|
||||||
this command displays a summary of unallocated disk space.
|
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
|
.TP
|
||||||
.B \-V, \-\-version
|
.B \-V, \-\-version
|
||||||
@@ -469,8 +479,13 @@ Non\-GPT disk detected and no \fI\-g\fR option
|
|||||||
.TP
|
.TP
|
||||||
.B 4
|
.B 4
|
||||||
An error prevented saving changes
|
An error prevented saving changes
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B 8
|
||||||
|
Disk replication operation (-R) failed
|
||||||
|
|
||||||
.SH "BUGS"
|
.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:
|
should be considered beta software. Known bugs and limitations include:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@@ -546,10 +561,6 @@ options in this case.
|
|||||||
|
|
||||||
.PP
|
.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"
|
.SH "AUTHORS"
|
||||||
Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
|
Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||||
|
|
||||||
@@ -568,6 +579,7 @@ Contributors:
|
|||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
\fBcfdisk (8)\fR,
|
\fBcfdisk (8)\fR,
|
||||||
|
\fBcgdisk (8)\fR,
|
||||||
\fBfdisk (8)\fR,
|
\fBfdisk (8)\fR,
|
||||||
\fBgdisk (8)\fR,
|
\fBgdisk (8)\fR,
|
||||||
\fBmkfs (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
|
/* 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. */
|
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "gptcl.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"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#define MAX_OPTIONS 50
|
#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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
GPTData theGPT, secondDevice;
|
GPTDataCL theGPT;
|
||||||
uint32_t sSize;
|
return theGPT.DoOptions(argc, argv);
|
||||||
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;
|
|
||||||
} // main
|
} // 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
|
// to 2. If value includes a "+", adds low and subtracts 1; if SIValue
|
||||||
// inclues a "-", subtracts from high. If IeeeValue is empty, returns def.
|
// inclues a "-", subtracts from high. If IeeeValue is empty, returns def.
|
||||||
// Returns final sector value. In case inValue is invalid, returns 0 (a
|
// 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
|
// inValue works out to something outside the range low-high, returns the
|
||||||
// computed value; the calling function is responsible for checking the
|
// computed value; the calling function is responsible for checking the
|
||||||
// validity of this value.
|
// validity of this value.
|
||||||
@@ -304,3 +304,19 @@ void ReverseBytes(void* theValue, int numBytes) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
} // if/else
|
} // if/else
|
||||||
} // ReverseBytes()
|
} // 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
|
#ifndef __GPTSUPPORT
|
||||||
#define __GPTSUPPORT
|
#define __GPTSUPPORT
|
||||||
|
|
||||||
#define GPTFDISK_VERSION "0.7.2"
|
#define GPTFDISK_VERSION "0.8.0"
|
||||||
|
|
||||||
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
|
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
|
||||||
// Darwin (Mac OS) & FreeBSD: disk IOCTLs are different, and there is no lseek64
|
// 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);
|
char GetYN(void);
|
||||||
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
|
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);
|
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);
|
unsigned char StrToHex(const string & input, unsigned int position);
|
||||||
int IsHex(string input); // Returns 1 if input can be hexadecimal number....
|
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
|
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 ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue
|
||||||
|
void WinWarning(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user