GPT fdisk 0.5.0
Added several features, including a restructuring of the menu system, GPT-to-MBR conversion, and the ability to re-read the MBR to generate a fresh GPT from the current on-disk MBR.
This commit is contained in:
42
CHANGELOG
42
CHANGELOG
@@ -1,3 +1,45 @@
|
|||||||
|
0.5.0:
|
||||||
|
------
|
||||||
|
|
||||||
|
- Added GPT-to-MBR conversion function. It's very limited, but potentially
|
||||||
|
useful in some cases.
|
||||||
|
|
||||||
|
- Fixed bug that caused incorrect file sizes to be reported on 32-bit
|
||||||
|
Linux, thus causing problems when editing partition tables in disk images
|
||||||
|
or when loading GPT backup files.
|
||||||
|
|
||||||
|
- Fixed bug that caused bogus CRC error reports when loading backup GPT
|
||||||
|
data.
|
||||||
|
|
||||||
|
- Reorganized menus. There are now three: the main menu, the experts' menu,
|
||||||
|
and the recovery & transformation menu. The last of these has most of the
|
||||||
|
items that had been on the earlier versions' experts' menu.
|
||||||
|
|
||||||
|
- Added ability to re-load the MBR and generate a fresh GPT from it. This
|
||||||
|
is normally identical to quitting and re-running the program, but it
|
||||||
|
could be handy if, say, the GPT partitions on a hybrid configuration are
|
||||||
|
badly messed up; this will enable using the hybridized partitions as the
|
||||||
|
starting point for a new GPT setup.
|
||||||
|
|
||||||
|
- The program now generates CHS values for hybrid and GPT-to-MBR conversion
|
||||||
|
MBRs. For the moment, the assumption is the maximum number of heads and
|
||||||
|
sectors per track (255 and 63, respectively), although the bulk of the
|
||||||
|
code supports other values -- it'd just be awkward to enter the data in
|
||||||
|
the user interface.
|
||||||
|
|
||||||
|
- Fixed minor display bug that caused number of sectors on the disk to be
|
||||||
|
shown as 0 on large disks when running 32-bit binaries.
|
||||||
|
|
||||||
|
- Reverted 0.4.2's zap (destroy GPT) changes, since I don't want to wipe
|
||||||
|
out a valid MBR if the user created that MBR over an older GPT without
|
||||||
|
first properly wiping out the GPT, and the user now wants to wipe out
|
||||||
|
the GPT.
|
||||||
|
|
||||||
|
- Reformatted and edited the man page. Aside from edits related to the
|
||||||
|
preceding program changes, I've altered the markup slightly and trimmed
|
||||||
|
much of the more tutorial information from the man page to better
|
||||||
|
conform to typical terse man page style.
|
||||||
|
|
||||||
0.4.2:
|
0.4.2:
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|||||||
666
gdisk.8
666
gdisk.8
@@ -1,242 +1,108 @@
|
|||||||
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
|
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||||
.\" May be distributed under the GNU General Public License
|
.\" May be distributed under the GNU General Public License
|
||||||
.TH GDISK 8 "August 2009" "0.4.2" "GPT fdisk Manual"
|
.TH "GDISK" "8" "0.5.0" "Roderick W. Smith" "GPT fdisk Manual"
|
||||||
.SH NAME
|
.SH "NAME"
|
||||||
gdisk \- GPT partition table manipulator for Linux and Unix
|
gdisk \- GPT partition table manipulator for Linux and Unix
|
||||||
.SH SYNOPSIS
|
.SH "SYNOPSIS"
|
||||||
.BI "gdisk "
|
.BI "gdisk "
|
||||||
[ \-l ]
|
[ \-l ]
|
||||||
.I device
|
.I device
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH "DESCRIPTION"
|
||||||
|
|
||||||
Hard disks can be divided into one or more segments, known as
|
GPT fdisk (aka \fBgdisk\fR) is a text\-mode menu\-driven program for
|
||||||
.IR partitions .
|
creation and manipulation of partition tables. It will automatically
|
||||||
This division is described in the
|
convert an old\-style Master Boot Record (MBR) partition table or BSD
|
||||||
.I "partition table"
|
disklabel stored without an MBR carrier partition to the newer Globally
|
||||||
of the disk. Several different partition table formats exist, each with its
|
Unique Identifier (GUID) Partition Table (GPT) format, or will load a GPT
|
||||||
advantages and disadvantages.
|
partition table. When used with the \fI\-l\fR command\-line option, the
|
||||||
|
program displays the current partition table and then exits.
|
||||||
|
|
||||||
The original partitioning system used on PCs, now known as the
|
GPT fdisk operates mainly on the GPT headers and partition tables; however,
|
||||||
.IR "MBR partitioning scheme",
|
|
||||||
is subject to several limitations. These include an awkward distinction
|
|
||||||
between
|
|
||||||
.IR "primary",
|
|
||||||
.IR "extended",
|
|
||||||
and
|
|
||||||
.IR "logical"
|
|
||||||
partitions; no redundancy or error correction capabilities; and 32-bit data
|
|
||||||
structures that, in conjunction with the common 512-byte sector size,
|
|
||||||
impose a hard 2 TiB limit on the size of partitions and disks. This final
|
|
||||||
drawback makes MBR partitions unsuitable for use on large hardware RAID
|
|
||||||
arrays. Individual disk sizes are expected to surpass the 2 TiB limit in
|
|
||||||
2009, so MBR will become an unsuitable partitioning system even for
|
|
||||||
individual hard disks in the near future.
|
|
||||||
|
|
||||||
The successor to MBR partitions is the
|
|
||||||
.IR "Globally Unique Identifier (GUID) Partition Table (GPT)"
|
|
||||||
system. GPT addresses each of the major limitations of MBR partitions, and
|
|
||||||
includes a dummy MBR partition table with a single
|
|
||||||
.IR "protective MBR"
|
|
||||||
entry to keep GPT-unaware programs from modifying the disk's GPT partitions. GPT
|
|
||||||
is a new partitioning scheme, though, and as such, older utilities and OSes
|
|
||||||
must be replaced or modified to handle GPT. Linux's venerable
|
|
||||||
.B "fdisk"
|
|
||||||
program, in particular, cannot process GPT disks. (The same is true of
|
|
||||||
related programs, such as
|
|
||||||
.B "sfdisk"
|
|
||||||
and
|
|
||||||
.BR "cfdisk".)
|
|
||||||
The alternative GNU
|
|
||||||
Parted and related programs, however, are capable of working on both MBR
|
|
||||||
and GPT disks.
|
|
||||||
|
|
||||||
GPT is often associated with the
|
|
||||||
.IR "Extensible Firmware Interface (EFI)",
|
|
||||||
which is Intel's intended successor to the traditional (legacy) PC BIOS. It
|
|
||||||
is possible to use and even boot from GPT disks on non-EFI systems,
|
|
||||||
including those that use a legacy BIOS. Using GPT disks on such a system
|
|
||||||
isn't a great challenge, although the OS must support GPT. Booting from a
|
|
||||||
GPT-based disk requires that the OS support this action, and if the system
|
|
||||||
is BIOS-based, a GPT-aware boot loader is required. Patched versions of the
|
|
||||||
.IR "Grand Unified Bootloader (GRUB)"
|
|
||||||
0.97, as well as GRUB2, support GPT.
|
|
||||||
|
|
||||||
GPT creates five distinct data structures of three types:
|
|
||||||
.TP
|
|
||||||
.B "Protective MBR"
|
|
||||||
The first sector (512 bytes) of the disk is devoted to an MBR that
|
|
||||||
consists of a single partition spanning the entire disk (or 2 TiB for disks
|
|
||||||
larger than this). The protective MBR may optionally include first-stage
|
|
||||||
boot loader code.
|
|
||||||
.TP
|
|
||||||
.B "GPT headers"
|
|
||||||
Two GPT headers exist, a main header and a backup header. The primary
|
|
||||||
header resides immediately after the protective MBR, and the backup header
|
|
||||||
is stored on the last sector of the disk. These headers contain disk
|
|
||||||
metadata, such as the location of the partition table, the size of the
|
|
||||||
partition table, and a "serial number" (GUID) that should be unique for
|
|
||||||
each disk. Each GPT header also stores two CRC checksums, one for the
|
|
||||||
partition table and one for the GPT header itself.
|
|
||||||
.TP
|
|
||||||
.B "Partition tables"
|
|
||||||
Each GPT header points to one partition table. The main partition table
|
|
||||||
appears immediately after the main GPT header, and the backup partition
|
|
||||||
table comes immediately before its GPT header. Typically, the partition
|
|
||||||
tables may hold data on up to 128 partitions, although
|
|
||||||
.B gdisk
|
|
||||||
enables you to change this value. Each entry contains 64-bit start and stop
|
|
||||||
sector numbers, a name, a partition GUID type code, a unique partition GUID
|
|
||||||
identifier, and additional data.
|
|
||||||
.PP
|
|
||||||
|
|
||||||
The GPT fdisk (aka
|
|
||||||
.BR "gdisk")
|
|
||||||
program operates mainly on the GPT headers and partition tables; however,
|
|
||||||
it can and will generate a fresh protective MBR, when required. (Any boot
|
it can and will generate a fresh protective MBR, when required. (Any boot
|
||||||
loader code in the protective MBR will not be disturbed.) If you've created
|
loader code in the protective MBR will not be disturbed.) If you've created
|
||||||
an unusual protective MBR, such as a hybrid MBR created by
|
an unusual protective MBR, such as a hybrid MBR created by
|
||||||
.IR "gptsync"
|
\fBgptsync\fR or \fBgdisk\fR's own hybrid MBR creation feature,
|
||||||
or
|
|
||||||
.BR "gdisk"'s
|
|
||||||
own hybrid MBR creation feature,
|
|
||||||
this should not be disturbed by most ordinary actions. Some advanced data
|
this should not be disturbed by most ordinary actions. Some advanced data
|
||||||
recovery options require you to understand the distinctions between the
|
recovery options require you to understand the distinctions between the
|
||||||
main and backup data, as well as between the GPT headers and the partition
|
main and backup data, as well as between the GPT headers and the partition
|
||||||
tables.
|
tables. For information on MBR vs. GPT, as well as GPT terminology and
|
||||||
|
structure, see the extended \fBgdisk\fR documentation at
|
||||||
|
\fIhttp://www.rodsbooks.com/gdisk/\fR or consult Wikipedia.
|
||||||
|
|
||||||
The
|
The \fBgdisk\fR program employs a user interface similar to that of Linux's
|
||||||
.B "gdisk"
|
\fBfdisk\fR, but \fBgdisk\fR
|
||||||
program employs a user interface similar to that of Linux's
|
|
||||||
.BR "fdisk",
|
|
||||||
but
|
|
||||||
.B "gdisk"
|
|
||||||
modifies GPT partitions. It also has the capability of transforming MBR
|
modifies GPT partitions. It also has the capability of transforming MBR
|
||||||
partitions or BSD disklabels into GPT partitions. Like the original
|
partitions or BSD disklabels into GPT partitions. Like the original
|
||||||
.B fdisk
|
\fBfdisk\fR program, \fBgdisk\fR
|
||||||
program,
|
|
||||||
.B gdisk
|
|
||||||
does not modify disk structures until you explicitly write them to disk, so
|
does not modify disk structures until you explicitly write them to disk, so
|
||||||
if you make a mistake, you can exit from the program with the 'q' option to
|
if you make a mistake, you can exit from the program with the 'q' option to
|
||||||
save your partitions.
|
save your partitions.
|
||||||
|
|
||||||
.B gdisk
|
Ordinarily, \fBgdisk\fR operates on disk device files, such as
|
||||||
is a text-mode menu-driven program for creation and manipulation of
|
\fI/dev/sda\fR or \fI/dev/hda\fR under Linux, \fI/dev/disk0\fR under
|
||||||
partition tables. It will automatically convert an MBR partition table or
|
Mac OS X, or \fI/dev/ad0\fR or \fI/dev/da0\fR under FreeBSD. The program
|
||||||
BSD disklabel stored without an MBR carrier partition to GPT format, or
|
can also operate on disk image files, which can be either copies of whole
|
||||||
will load a GPT partition table. When used with the
|
disks (made with \fBdd\fR, for instance) or raw disk images used by
|
||||||
.IR "\-l"
|
emulators such as QEMU or VMWare. Note that only \fIraw\fR disk images
|
||||||
command-line option, the program displays the current partition table and
|
are supported; \fBgdisk\fR cannot work on compressed or other advanced
|
||||||
then exits.
|
disk image formats.
|
||||||
|
|
||||||
Linux hard disk device filenames take the form
|
|
||||||
.IR "/dev/sdx"
|
|
||||||
or
|
|
||||||
.IR "/dev/hdx",
|
|
||||||
where
|
|
||||||
.IR "x"
|
|
||||||
is a letter from
|
|
||||||
.IR "a"
|
|
||||||
onward. The
|
|
||||||
.IR "hdx"
|
|
||||||
devices originally referred to IDE (aka PATA) drives, whereas
|
|
||||||
.IR "sdx"
|
|
||||||
devices originally referred to SCSI drives. These distinctions are now
|
|
||||||
blurring. Modern SATA drives and USB flash drives usually acquire
|
|
||||||
.IR "sdx"
|
|
||||||
names, and the same can even be true of PATA drives, depending on kernel
|
|
||||||
driver options. For instance,
|
|
||||||
.IR "/dev/hda"
|
|
||||||
refers to the first PATA drive, whereas
|
|
||||||
.IR "/dev/sdb"
|
|
||||||
is the second SCSI, SATA, USB, or other SCSI-equivalent drive. To use
|
|
||||||
.BR "gdisk",
|
|
||||||
you must pass a device filename to the program on the command line.
|
|
||||||
|
|
||||||
The
|
|
||||||
.I partition
|
|
||||||
is a
|
|
||||||
device name followed by a partition number. For example,
|
|
||||||
.B /dev/hda1
|
|
||||||
is the first partition on the first PATA hard disk.
|
|
||||||
.B gdisk
|
|
||||||
creates partitions, but you don't pass partition numbers or partition
|
|
||||||
device filenames to the program. Linux generates numbers for GPT partitions
|
|
||||||
based on the partition's position in the partition table.
|
|
||||||
|
|
||||||
The MBR partitioning system uses a combination of cylinder/head/sector
|
The MBR partitioning system uses a combination of cylinder/head/sector
|
||||||
(CHS) addressing and logical block addressing (LBA). The former is klunky
|
(CHS) addressing and logical block addressing (LBA). The former is klunky
|
||||||
and limiting. GPT drops CHS addressing and uses 64-bit LBA mode
|
and limiting. GPT drops CHS addressing and uses 64\-bit LBA mode
|
||||||
exclusively. Thus, GPT data structures, and therefore
|
exclusively. Thus, GPT data structures, and therefore
|
||||||
.BR "gdisk",
|
\fBgdisk\fR, do not need to deal with CHS geometries and all the problems
|
||||||
do not need to deal with CHS geometries and all the problems they create.
|
they create. Users of \fBfdisk\fR will note that \fBgdisk\fR
|
||||||
Users of
|
|
||||||
.BR "fdisk"
|
|
||||||
will note that
|
|
||||||
.B "gdisk"
|
|
||||||
lacks the options and limitations associated with CHS geometries.
|
lacks the options and limitations associated with CHS geometries.
|
||||||
|
|
||||||
For best results, you should always use an OS-specific partition table
|
For best results, you should use an OS\-specific partition table
|
||||||
program. For example, you should make Mac OS X partitions with the Mac OS
|
program whenever possible. For example, you should make Mac OS X
|
||||||
X Disk Utility
|
partitions with the Mac OS X Disk Utility program and Linux partitions
|
||||||
program and Linux partitions with the Linux
|
with the Linux \fBgdisk\fR or GNU Parted program.
|
||||||
.B "gdisk"
|
|
||||||
or GNU Parted program.
|
|
||||||
|
|
||||||
Upon start,
|
Upon start, \fBgdisk\fR attempts to identify the partition type in use
|
||||||
.B gdisk
|
on the disk. If it finds valid GPT data, \fBgdisk\fR
|
||||||
attempts to identify the partition type in use on the specified disk. If it
|
will use it. If \fBgdisk\fR
|
||||||
finds valid GPT data,
|
|
||||||
.B gdisk
|
|
||||||
will use it. If
|
|
||||||
.B gdisk
|
|
||||||
finds a valid MBR or BSD disklabel but no GPT data, it will attempt to
|
finds a valid MBR or BSD disklabel but no GPT data, it will attempt to
|
||||||
convert the MBR or disklabel into GPT form. (BSD disklabels are likely to
|
convert the MBR or disklabel into GPT form. (BSD disklabels are likely to
|
||||||
have unusable first and/or final partitions because they overlap with the
|
have unusable first and/or final partitions because they overlap with the
|
||||||
GPT data structures, though.) GPT fdisk can identify, but not use data in,
|
GPT data structures, though.) GPT fdisk can identify, but not use data in,
|
||||||
Apple Partition Map (APM) disks, which are used on 680x0- and PowerPC-based
|
Apple Partition Map (APM) disks, which are used on 680x0\- and PowerPC\-based
|
||||||
Macintoshes. Upon exiting with the 'w' option,
|
Macintoshes. Upon exiting with the 'w' option, \fBgdisk\fR replaces
|
||||||
.B gdisk
|
the MBR or disklabel with a GPT. \fIThis action is potentially dangerous!\fR
|
||||||
will then replace the MBR or disklabel with a GPT.
|
|
||||||
.IR "This action is potentially dangerous!"
|
|
||||||
Your system may become unbootable, and partition type codes may become
|
Your system may become unbootable, and partition type codes may become
|
||||||
corrupted if the disk uses unrecognized type codes. Boot problems are
|
corrupted if the disk uses unrecognized type codes. Boot problems are
|
||||||
particularly likely if you're multi-booting with any GPT-unaware OS. If you
|
particularly likely if you're multi\-booting with any GPT\-unaware OS. If you
|
||||||
mistakenly launch
|
mistakenly launch \fBgdisk\fR on an MBR disk, you can safely exit
|
||||||
.B gdisk
|
the program without making any changes by using the 'q' option.
|
||||||
on an MBR disk, you can safely exit the program
|
|
||||||
without making any changes by using the 'q' option.
|
|
||||||
|
|
||||||
The MBR-to-GPT conversion will leave at least one gap in the partition
|
The MBR\-to\-GPT conversion will leave at least one gap in the partition
|
||||||
numbering if the original MBR used logical partitions. These gaps are
|
numbering if the original MBR used logical partitions. These gaps are
|
||||||
harmless, but you can eliminate them by using the 's' option, if you like.
|
harmless, but you can eliminate them by using the 's' option, if you like.
|
||||||
(Doing this may require you to update your
|
(Doing this may require you to update your \fI/etc/fstab\fR file.)
|
||||||
.IR "/etc/fstab"
|
|
||||||
file.)
|
|
||||||
|
|
||||||
When creating a fresh partition table, certain considerations may be in
|
When creating a fresh partition table, certain considerations may be in
|
||||||
order:
|
order:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
For data (non-boot) disks, and for boot disks used on BIOS-based computers
|
For data (non\-boot) disks, and for boot disks used on BIOS\-based computers
|
||||||
with GRUB as the boot loader, partitions may be created in whatever order
|
with GRUB as the boot loader, partitions may be created in whatever order
|
||||||
and in whatever sizes are desired.
|
and in whatever sizes are desired.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
Boot disks for EFI-based systems require an "EFI System
|
Boot disks for EFI\-based systems require an \fIEFI System
|
||||||
Partition" (
|
Partition\fR (\fBgdisk\fR internal code 0xEF00) formatted as FAT\-32.
|
||||||
.B "gdisk"
|
The recommended size of this partition between 100 and 200 MiB.
|
||||||
internal code 0xEF00) formatted as FAT-32. The recommended size of this
|
Boot\-related files are stored here. (Note that GNU Parted identifies
|
||||||
partition is 100 MiB. Boot-related files are stored here. (Note that GNU
|
such partitions as having the "boot flag" set.)
|
||||||
Parted identifies such partitions as having the "boot flag" set.)
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
Some boot loaders for BIOS-based systems make use of a "BIOS Boot
|
Some boot loaders for BIOS\-based systems make use of a \fIBIOS Boot
|
||||||
Partition" (
|
Partition\fR (\fBgdisk\fR
|
||||||
.B "gdisk"
|
|
||||||
internal code 0xEF02), in which the secondary boot loader is stored,
|
internal code 0xEF02), in which the secondary boot loader is stored,
|
||||||
possibly without the benefit of a filesystem. This partition can
|
possibly without the benefit of a filesystem. This partition can
|
||||||
typically be quite small (a few tens of kilobytes), but you should
|
typically be quite small (a few tens of kilobytes), but you should
|
||||||
@@ -244,9 +110,8 @@ consult your boot loader documentation for details.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
If Windows is to boot from a GPT disk, a partition of type "Microsoft
|
If Windows is to boot from a GPT disk, a partition of type \fIMicrosoft
|
||||||
Reserved" (
|
Reserved\fR (\fBgdisk\fR
|
||||||
.B "gdisk"
|
|
||||||
internal code 0x0C01) is recommended. This partition should be about 128 MiB
|
internal code 0x0C01) is recommended. This partition should be about 128 MiB
|
||||||
in size. It ordinarily follows the EFI System Partition and immediately
|
in size. It ordinarily follows the EFI System Partition and immediately
|
||||||
precedes the Windows data partitions. (Note that GNU Parted creates all
|
precedes the Windows data partitions. (Note that GNU Parted creates all
|
||||||
@@ -262,34 +127,31 @@ help in future disk maintenance. You can use GPT fdisk's relative partition
|
|||||||
positioning option (specifying the starting sector as '+128M', for
|
positioning option (specifying the starting sector as '+128M', for
|
||||||
instance) to simplify creating such gaps.
|
instance) to simplify creating such gaps.
|
||||||
|
|
||||||
.SH OPTIONS
|
.SH "OPTIONS"
|
||||||
.TP
|
.TP
|
||||||
.B \-l
|
.B \-l
|
||||||
List the partition tables for the specified devices and then exit.
|
List the partition tables for the specified devices and then exit.
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
Most interactions with
|
Most interactions with \fBgdisk\fR
|
||||||
.B gdisk
|
occur with its interactive text\-mode menus. Three menus exist: the main
|
||||||
occur with its interactive text-mode menus. The main menu provides the
|
menu, the recovery & transformation menu, and the experts' menu. The main
|
||||||
following options:
|
menu provides the functions that are most likely to be useful for typical partitioning tasks, such as creating and deleting partitions, changing partition type codes, and so on. Specific functions are:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B b
|
.B b
|
||||||
Convert BSD partitions into GPT partitions. This option works on BSD
|
Save partition data to a backup file. You can back up your partition table
|
||||||
disklabels held within GPT (or converted MBR) partitions. Converted
|
to a disk file using this option. The resulting file is a binary file
|
||||||
partitions' type codes are likely to need manual adjustment.
|
consisting of the protective MBR, the main GPT header, the backup GPT
|
||||||
.B gdisk
|
header, and one copy of the partition table, in that order. Note that the
|
||||||
will attempt to convert BSD disklabels stored on the main disk when
|
restore option is on the recovery & transformation menu; the backup
|
||||||
launched, but this conversion is likely to produce first and/or last
|
option is on the main menu to encourage its use.
|
||||||
partitions that are unusable. The many BSD variants means that the
|
|
||||||
probability of GPT fdisk being unable to convert a BSD disklabel are high
|
|
||||||
compared to the likelihood of problems with an MBR conversion.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B c
|
.B c
|
||||||
Change the GPT name of a partition. This name is encoded as a UTF-16
|
Change the GPT name of a partition. This name is encoded as a UTF\-16
|
||||||
string, but
|
string, but \fBgdisk\fR
|
||||||
.B gdisk
|
|
||||||
supports only ASCII characters as names. For the most part, Linux ignores
|
supports only ASCII characters as names. For the most part, Linux ignores
|
||||||
the partition name, but it may be important in some OSes. GPT fdisk sets
|
the partition name, but it may be important in some OSes. GPT fdisk sets
|
||||||
a default name based on the partition type code.
|
a default name based on the partition type code.
|
||||||
@@ -299,16 +161,14 @@ a default name based on the partition type code.
|
|||||||
Delete a partition. This action deletes the entry from the partition table
|
Delete a partition. This action deletes the entry from the partition table
|
||||||
but does not disturb the data within the sectors originally allocated to
|
but does not disturb the data within the sectors originally allocated to
|
||||||
the partition on the disk. If a corresponding hybrid MBR partition exists,
|
the partition on the disk. If a corresponding hybrid MBR partition exists,
|
||||||
.B gdisk
|
\fBgdisk\fR deletes it, as well, and expands any adjacent 0xEE (EFI GPT)
|
||||||
deletes it, as well, and expands any adjacent 0xEE (EFI GPT) MBR protective
|
MBR protective partition to fill the new free space.
|
||||||
partition to fill the new free space.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B i
|
.B i
|
||||||
Show detailed partition information. The summary information produced by
|
Show detailed partition information. The summary information produced by
|
||||||
the 'p' command necessarily omits many details, such as the partition's
|
the 'p' command necessarily omits many details, such as the partition's
|
||||||
unique GUID and the translation of
|
unique GUID and the translation of \fBgdisk\fR's
|
||||||
.BR "gdisk"'s
|
|
||||||
internal partition type code to a plain type name. The 'i' option
|
internal partition type code to a plain type name. The 'i' option
|
||||||
displays this information for a single partition.
|
displays this information for a single partition.
|
||||||
|
|
||||||
@@ -316,45 +176,30 @@ displays this information for a single partition.
|
|||||||
.B l
|
.B l
|
||||||
Display a summary of partition types. GPT uses a GUID to identify
|
Display a summary of partition types. GPT uses a GUID to identify
|
||||||
partition types for particular OSes and purposes. For ease of data entry,
|
partition types for particular OSes and purposes. For ease of data entry,
|
||||||
.B gdisk
|
\fBgdisk\fR compresses these into two\-byte (four\-digit hexadecimal)
|
||||||
compresses these into two-byte (four-digit hexadecimal) values that are
|
values that are related to their equivalent MBR codes. Specifically, the
|
||||||
related to their MBR codes. Specifically, the MBR code is multiplied by
|
MBR code is multiplied by hexadecimal 0x0100. For instance, the code for
|
||||||
hexadecimal 0x0100. For instance, the code for Linux swap space in MBR is
|
Linux swap space in MBR is 0x82, and it's 0x8200 in \fBgdisk\fR.
|
||||||
0x82, and it's 0x8200 in
|
A one\-to\-one correspondence is impossible, though. Most notably, many DOS,
|
||||||
.BR "gdisk".
|
|
||||||
A one-to-one correspondence is impossible, though. Most notably, many DOS,
|
|
||||||
Windows, and Linux data partition codes correspond to a single GPT code
|
Windows, and Linux data partition codes correspond to a single GPT code
|
||||||
(entered as 0x0700 in
|
(entered as 0x0700 in \fBgdisk\fR). Some OSes use a single MBR code but
|
||||||
.BR "gdisk" ).
|
employ many more codes in GPT. For these, \fBgdisk\fR
|
||||||
Some OSes use a single MBR code but employ many more codes in GPT. For
|
|
||||||
these,
|
|
||||||
.B gdisk
|
|
||||||
adds code numbers sequentially, such as 0xa500 for a FreeBSD disklabel,
|
adds code numbers sequentially, such as 0xa500 for a FreeBSD disklabel,
|
||||||
0xa501 for FreeBSD boot, 0xa502 for FreeBSD swap, and so on. Note that
|
0xa501 for FreeBSD boot, 0xa502 for FreeBSD swap, and so on. Note that
|
||||||
these two-byte codes are unique to
|
these two\-byte codes are unique to \fBgdisk\fR.
|
||||||
.BR "gdisk".
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B m
|
|
||||||
Print the menu. Type this command (or any other unrecognized command) to
|
|
||||||
see a summary of available options.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B n
|
.B n
|
||||||
Create a new partition. This command is modelled after the equivalent
|
Create a new partition. This command is modelled after the equivalent
|
||||||
.B fdisk
|
\fBfdisk\fR option, although some differences exist. You enter a partition
|
||||||
option, although some differences exist. You enter a partition number,
|
number, starting sector, and an ending sector. Both start and end sectors
|
||||||
starting sector, and an ending sector. Both start and end sectors can be
|
can be specified in absolute terms as sector numbers or as positions measured
|
||||||
specified in absolute terms as sector numbers or as positions measured in
|
in kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T); for
|
||||||
kilobytes (K), megabytes (M), gigabytes (G), or terabytes (T); for
|
instance, \fI\fB40M\fR\fR
|
||||||
instance,
|
|
||||||
.BI 40M
|
|
||||||
specifies a position 40MiB from the start of the disk. You can specify
|
specifies a position 40MiB from the start of the disk. You can specify
|
||||||
locations relative to the start or end of the specified range by preceding
|
locations relative to the start or end of the specified range by preceding
|
||||||
the number by a '+' or '-' symbol, as in
|
the number by a '+' or '\-' symbol, as in \fI\fB+2G\fR\fR
|
||||||
.BI +2G
|
to specify a point 2GiB after the first available sector, or \fI\fB\-200M\fR\fR
|
||||||
to specify a point 2GiB after the first available sector, or
|
|
||||||
.BI -200M
|
|
||||||
to specify a point 200MiB before the last available sector. Pressing the
|
to specify a point 200MiB before the last available sector. Pressing the
|
||||||
Enter key with no input specifies the default value, which is the start of
|
Enter key with no input specifies the default value, which is the start of
|
||||||
the largest available block for the start sector and the last available
|
the largest available block for the start sector and the last available
|
||||||
@@ -369,42 +214,44 @@ all partition definitions, and the protective MBR.
|
|||||||
.B p
|
.B p
|
||||||
Display basic partition summary data. This includes partition
|
Display basic partition summary data. This includes partition
|
||||||
numbers, starting and ending sector numbers, partition sizes,
|
numbers, starting and ending sector numbers, partition sizes,
|
||||||
.BR "gdisk"'s
|
\fBgdisk\fR's partition types codes, and partition names. For
|
||||||
partition types codes, and partition names. For additional information,
|
additional information, use the 'i' command.
|
||||||
use the 'i' command.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B q
|
.B q
|
||||||
Quit from the program
|
Quit from the program \fIwithout saving your changes\fR.
|
||||||
.IR "without saving data".
|
|
||||||
Use this option if you just wanted to view information or if you make a
|
Use this option if you just wanted to view information or if you make a
|
||||||
mistake and want to back out of all your changes.
|
mistake and want to back out of all your changes.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B r
|
||||||
|
Enter the recovery & transformation menu. This menu includes emergency
|
||||||
|
recovery options (to fix damaged GPT data structures) and options to
|
||||||
|
transform to or from other partitioning systems, including creating
|
||||||
|
hybrid MBRs.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B s
|
.B s
|
||||||
Sort partition entries. GPT partition numbers need not match the order of
|
Sort partition entries. GPT partition numbers need not match the order of
|
||||||
partitions on the disk. If you want them to match, you can use this option.
|
partitions on the disk. If you want them to match, you can use this option.
|
||||||
Note that some partitioning utilities, such as GNU Parted, will sort
|
Note that some partitioning utilities sort
|
||||||
partitions whenever they make changes. Such changes will be reflected in
|
partitions whenever they make changes. Such changes will be reflected in
|
||||||
your device filenames, so you may need to edit
|
your device filenames, so you may need to edit
|
||||||
.IR "/etc/fstab"
|
\fI/etc/fstab\fR if you use this option.
|
||||||
if you use this option.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B t
|
.B t
|
||||||
Change a single partition's type code. You enter the type code using a
|
Change a single partition's type code. You enter the type code using a
|
||||||
two-byte hexadecimal number, as described earlier. You may also enter a
|
two\-byte hexadecimal number, as described earlier. You may also enter a
|
||||||
GUID directly, if you have one and
|
GUID directly, if you have one and \fBgdisk\fR doesn't know it.
|
||||||
.B gdisk
|
|
||||||
doesn't know it.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B v
|
.B v
|
||||||
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 these problems, though; for that, you must use
|
automatically correct most problems, though; for that, you must use
|
||||||
options on the experts' menu. If no problems are found, this command
|
options on the recovery & transformation menu. If no problems are found,
|
||||||
displays a summary of unallocated disk space.
|
this command displays a summary of unallocated disk space.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B w
|
.B w
|
||||||
@@ -416,33 +263,29 @@ Enter the experts' menu. Using this option provides access to features you
|
|||||||
can use to get into even more trouble than the main menu allows.
|
can use to get into even more trouble than the main menu allows.
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
A few options on the experts' menu duplicate functionality on the main
|
.TP
|
||||||
menu, for the sake of convenience; however, for the most part the experts'
|
.B ?
|
||||||
menu provides unusually dangerous or obscure options. These are:
|
Print the menu. Type this command (or any other unrecognized command) to
|
||||||
|
see a summary of available options.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
The second \fBgdisk\fR menu is the recovery & transformation menu, which
|
||||||
|
provides access to data recovery options and features related to the
|
||||||
|
transformation of partitions between partitioning schemes (converting
|
||||||
|
BSD disklabels into GPT partitions or creating hybrid MBRs, for instance).
|
||||||
|
A few options on this menu duplicate functionality on the main
|
||||||
|
menu, for the sake of convenience. The options on this menu are:
|
||||||
|
|
||||||
.TP
|
|
||||||
.B a
|
|
||||||
Set attributes. GPT provides a 64-bit attributes field that can be used to
|
|
||||||
set partition features.
|
|
||||||
.B gdisk
|
|
||||||
supports four attributes:
|
|
||||||
.IR "system partition",
|
|
||||||
.IR "read-only",
|
|
||||||
.IR "hidden",
|
|
||||||
and
|
|
||||||
.IR "do not automount".
|
|
||||||
You can set other attributes, but their numbers aren't translated into
|
|
||||||
anything useful. In practice, most OSes seem to ignore these attributes.
|
|
||||||
.TP
|
.TP
|
||||||
.B b
|
.B b
|
||||||
Rebuild main GPT header from backup. You can use the backup GPT header to
|
Rebuild GPT header from backup. You can use the backup GPT header to
|
||||||
rebuild the main GPT header with this option. It's likely to be useful if
|
rebuild the main GPT header with this option. It's likely to be useful if
|
||||||
your main GPT header was damaged or destroyed (say, by sloppy use of
|
your main GPT header was damaged or destroyed (say, by sloppy use of
|
||||||
.IR "dd").
|
\fBdd\fR).
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B c
|
.B c
|
||||||
Load backup partition table. Ordinarily,
|
Load backup partition table. Ordinarily, \fBgdisk\fR
|
||||||
.B gdisk
|
|
||||||
uses only the main partition table (although the backup's integrity is
|
uses only the main partition table (although the backup's integrity is
|
||||||
checked when you launch the program). If the main partition table has been
|
checked when you launch the program). If the main partition table has been
|
||||||
damaged, you can use this option to load the backup from disk and use it
|
damaged, you can use this option to load the backup from disk and use it
|
||||||
@@ -454,79 +297,168 @@ there will be no backup partition table on disk.
|
|||||||
.B d
|
.B d
|
||||||
Use main GPT header and rebuild the backup. This option is likely to be
|
Use main GPT header and rebuild the backup. This option is likely to be
|
||||||
useful if the backup GPT header has been damaged or destroyed.
|
useful if the backup GPT header has been damaged or destroyed.
|
||||||
.TP
|
|
||||||
|
|
||||||
|
.TP
|
||||||
.B e
|
.B e
|
||||||
Load main partition table. This option reloads the main partition table
|
Load main partition table. This option reloads the main partition table
|
||||||
from disk. It's only likely to be useful if you've tried to use the backup
|
from disk. It's only likely to be useful if you've tried to use the backup
|
||||||
partition table (via 'c') but it's in worse shape then the main partition
|
partition table (via 'c') but it's in worse shape then the main partition
|
||||||
table.
|
table.
|
||||||
.TP
|
|
||||||
|
|
||||||
|
.TP
|
||||||
.B f
|
.B f
|
||||||
Change partition GUID. You can enter a custom unique GUID for a partition
|
Load MBR and build fresh GPT from it. Use this option if your GPT is corrupt
|
||||||
using this option. (Note this refers to the GUID that uniquely identifies a
|
or conflicts with the MBR and you want to use the MBR as the basis for a new
|
||||||
partition, not to its type code.) Ordinarily,
|
set of GPT partitions.
|
||||||
.B gdisk
|
|
||||||
assigns this number randomly; however, you might want to adjust the number
|
|
||||||
manually if you've wound up with the same GUID on two partitions.
|
|
||||||
.TP
|
.TP
|
||||||
.B g
|
.B g
|
||||||
Change disk GUID. Each disk has a unique GUID code, which
|
Convert GPT into MBR and exit. This option converts up to four GPT partitions
|
||||||
.B gdisk
|
into MBR form, destroys the GPT data structures, saves the new MBR, and exits.
|
||||||
assigns randomly upon creation of the GPT data structures. You can generate
|
Use this option if you've tried GPT and find that MBR works better for you.
|
||||||
a fresh random GUID or enter one manually with this option.
|
Note that this function generates up to four \fIprimary\fR MBR partitions;
|
||||||
|
it cannot generate logical partitions, and so it cannot transform more than
|
||||||
|
four partitions. If four or fewer partitions exist, and if they can be represented
|
||||||
|
in the 32\-bit MBR LBA scheme, this function converts
|
||||||
|
them all. If more than four partitions exist, you'll be asked to select which
|
||||||
|
ones to convert. See also the 'h' option.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B h
|
.B h
|
||||||
Create a hybrid MBR. This is an ugly workaround that enables GPT-unaware
|
Create a hybrid MBR. This is an ugly workaround that enables GPT\-unaware
|
||||||
OSes, or that that can't boot from a GPT disk, to access up to three of
|
OSes, or those that can't boot from a GPT disk, to access up to three of
|
||||||
the partitions on the disk by creating MBR entries for them. Note that
|
the partitions on the disk by creating MBR entries for them. Note that
|
||||||
these hybrid MBR entries are not updated when you make subsequent changes
|
these hybrid MBR entries can easily go out of sync with the GPT entries,
|
||||||
to the GPT entries, so you must re-run this option whenever you make
|
particularly when hybrid\-unaware GPT utilities are used to edit the disk.
|
||||||
changes that would affect the hybridized partitions.
|
Thus, you may need to recreate the hybrid MBR if you use such tools.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B i
|
.B i
|
||||||
Show detailed partition information. This option is identical to the 'i'
|
Show detailed partition information. This option is identical to the 'i'
|
||||||
option on the main menu.
|
option on the main menu.
|
||||||
.TP
|
|
||||||
.B k
|
|
||||||
Save partition data to a backup file. You can back up your partition table
|
|
||||||
to a disk file using this option. The resulting file is a binary file
|
|
||||||
consisting of the protective MBR, the main GPT header, the backup GPT
|
|
||||||
header, and one copy of the partition table, in that order.
|
|
||||||
.TP
|
.TP
|
||||||
.B l
|
.B l
|
||||||
Load partition data from a backup file. This option is the reverse of the 'k'
|
Load partition data from a backup file. This option is the reverse of the 'b'
|
||||||
option. Note that restoring partition data from anything but the
|
option on the main menu. Note that restoring partition data from anything
|
||||||
original disk is not recommended.
|
but the original disk is not recommended.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B m
|
.B m
|
||||||
Print the menu. This option (or any unrecognized entry) displays a summary
|
Return to the main menu. This option enables you to enter main\-menu commands.
|
||||||
of the menu options.
|
|
||||||
.TP
|
|
||||||
.B n
|
|
||||||
Create a new protective MBR. Use this option if the current protective MBR
|
|
||||||
is damaged in a way that
|
|
||||||
.B gdisk
|
|
||||||
doesn't automatically detect and correct.
|
|
||||||
.TP
|
.TP
|
||||||
.B o
|
.B o
|
||||||
Print protective MBR data. You can see a summary of the protective MBR's
|
Print protective MBR data. You can see a summary of the protective MBR's
|
||||||
partitions with this option. This may enable you to spot glaring problems
|
partitions with this option. This may enable you to spot glaring problems
|
||||||
or help identify the partitions in a hybrid MBR.
|
or help identify the partitions in a hybrid MBR.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B p
|
.B p
|
||||||
Print the partition table. This option is identical to the 'p' option in
|
Print the partition table. This option is identical to the 'p' option in
|
||||||
the main menu.
|
the main menu.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B q
|
.B q
|
||||||
Quit without saving changes. This option is identical to the 'q' option in
|
Quit without saving changes. This option is identical to the 'q' option in
|
||||||
the main menu.
|
the main menu.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B t
|
||||||
|
Transform BSD partitions into GPT partitions. This option works on BSD
|
||||||
|
disklabels held within GPT (or converted MBR) partitions. Converted
|
||||||
|
partitions' type codes are likely to need manual adjustment. \fBgdisk\fR
|
||||||
|
will attempt to convert BSD disklabels stored on the main disk when
|
||||||
|
launched, but this conversion is likely to produce first and/or last
|
||||||
|
partitions that are unusable. The many BSD variants means that the
|
||||||
|
probability of \fBgdisk\fR being unable to convert a BSD disklabel is
|
||||||
|
high compared to the likelihood of problems with an MBR conversion.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B v
|
||||||
|
Verify disk. This option is identical to the 'v' option in the main menu.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B w
|
||||||
|
Write table to disk and exit. This option is identical to the 'w' option in
|
||||||
|
the main menu.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B x
|
||||||
|
Enter the experts' menu. This option is identical to the 'x' option in the
|
||||||
|
main menu.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B ?
|
||||||
|
Print the menu. This option (or any unrecognized entry) displays a summary
|
||||||
|
of the menu options.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
The third \fBgdisk\fR menu is the experts' menu. This menu provides advanced
|
||||||
|
options that aren't closely related to recovery or transformation between
|
||||||
|
partitioning systems. Its options are:
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B a
|
||||||
|
Set attributes. GPT provides a 64\-bit attributes field that can be used to
|
||||||
|
set features for each partition. \fBgdisk\fR supports four attributes:
|
||||||
|
\fIsystem partition\fR, \fIread\-only\fR, \fIhidden\fR, and
|
||||||
|
\fIdo not automount\fR. You can set other attributes, but their numbers
|
||||||
|
aren't translated into anything useful. In practice, most OSes seem to
|
||||||
|
ignore these attributes.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B c
|
||||||
|
Change partition GUID. You can enter a custom unique GUID for a partition
|
||||||
|
using this option. (Note this refers to the GUID that uniquely identifies a
|
||||||
|
partition, not to its type code, which you can change with the 't' main\-menu
|
||||||
|
option.) Ordinarily, \fBgdisk\fR assigns this number randomly; however,
|
||||||
|
you might want to adjust the number manually if you've wound up with the
|
||||||
|
same GUID on two partitions because of buggy GUID assignments (hopefully
|
||||||
|
not in \fBgdisk\fR) or sheer incredible coincidence.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B g
|
||||||
|
Change disk GUID. Each disk has a unique GUID code, which \fBgdisk\fR
|
||||||
|
assigns randomly upon creation of the GPT data structures. You can generate
|
||||||
|
a fresh random GUID or enter one manually with this option.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B i
|
||||||
|
Show detailed partition information. This option is identical to the 'i'
|
||||||
|
option on the main menu.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B m
|
||||||
|
Return to the main menu. This option enables you to enter main\-menu commands.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B n
|
||||||
|
Create a new protective MBR. Use this option if the current protective MBR
|
||||||
|
is damaged in a way that \fBgdisk\fR doesn't automatically detect and
|
||||||
|
correct, or if you want to convert a hybrid MBR into a "pure" GPT with a
|
||||||
|
conventional protective MBR.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B o
|
||||||
|
Print protective MBR data. You can see a summary of the protective MBR's
|
||||||
|
partitions with this option. This may enable you to spot glaring problems
|
||||||
|
or help identify the partitions in a hybrid MBR.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B p
|
||||||
|
Print the partition table. This option is identical to the 'p' option in
|
||||||
|
the main menu.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B q
|
||||||
|
Quit without saving changes. This option is identical to the 'q' option in
|
||||||
|
the main menu.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B r
|
.B r
|
||||||
Return to the main menu. You can go back to the main menu with this option.
|
Enter the recovery & transformations menu. This option is identical to
|
||||||
|
the 'r' option on the main menu.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B s
|
.B s
|
||||||
@@ -540,51 +472,47 @@ partitions, though.
|
|||||||
.TP
|
.TP
|
||||||
.B v
|
.B v
|
||||||
Verify disk. This option is identical to the 'v' option in the main menu.
|
Verify disk. This option is identical to the 'v' option in the main menu.
|
||||||
.TP
|
|
||||||
.B w
|
|
||||||
Write table to disk and exit. This option is identical to the 'w' option in
|
|
||||||
the main menu.
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B z
|
.B z
|
||||||
Destroy the GPT data structures and exit. Use this option if you want to
|
Zap (destroy) the GPT data structures and exit. Use this option if you want to
|
||||||
repartition a GPT disk using
|
repartition a GPT disk using \fBfdisk\fR or some other GPT\-unaware program.
|
||||||
.B "fdisk"
|
|
||||||
or some other GPT-unaware program.
|
|
||||||
You'll be given the choice of preserving the existing MBR, in case it's a
|
You'll be given the choice of preserving the existing MBR, in case it's a
|
||||||
hybrid MBR with salvageable partitions.
|
hybrid MBR with salvageable partitions or if you've already created new MBR
|
||||||
|
partitions and want to erase the remnants of your GPT partitions. \fIIf you've
|
||||||
|
already created new MBR partitions, it's conceivable that this option will
|
||||||
|
damage the first and/or last MBR partitions!\fR Such an event is unlikely, but
|
||||||
|
could occur if your new MBR partitions overlap the old GPT data structures.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B ?
|
||||||
|
Print the menu. This option (or any unrecognized entry) displays a summary
|
||||||
|
of the menu options.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
In many cases, you can press the Enter key to select a default option when
|
In many cases, you can press the Enter key to select a default option when
|
||||||
entering data. When only one option is possible,
|
entering data. When only one option is possible, \fBgdisk\fR
|
||||||
.B gdisk
|
|
||||||
usually bypasses the prompt entirely.
|
usually bypasses the prompt entirely.
|
||||||
|
|
||||||
.SH BUGS
|
.SH "BUGS"
|
||||||
As of September 2009 (version 0.4.2),
|
As of September 2009 (version 0.5.0), \fBgdisk\fR
|
||||||
.B gdisk
|
|
||||||
should be considered beta software. Known bugs and limitations include:
|
should be considered beta software. Known bugs and limitations include:
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
The program compiles correctly only on Linux, FreeBSD, and Mac OS X. Both
|
The program compiles correctly only on Linux, FreeBSD, and Mac OS X. Linux
|
||||||
64-bit (x86-64) and 32-bit (x86) versions for Linux have been tested, the
|
versions for x86\-64 (64\-bit), x86 (32\-bit), and PowerPC (32\-bit) have been
|
||||||
former more thoroughly than the latter. The Mac OS X support was added with
|
tested, with the x86\-64 version having seen the most testing. The Mac OS X
|
||||||
version 0.3.1 and has not been as thoroughly tested. FreeBSD support was
|
support was added with version 0.3.1 and has not been as thoroughly tested.
|
||||||
added with version 0.4.0 and has not been very thoroughly tested.
|
FreeBSD support was added with version 0.4.0 and has seen even less
|
||||||
|
testing.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
The FreeBSD version of the program can't write changes to the partition
|
The FreeBSD version of the program can't write changes to the partition
|
||||||
table to a disk when existing partitions on that disk are mounted. (The
|
table to a disk when existing partitions on that disk are mounted. (The
|
||||||
same problem exists with many other FreeBSD utilities, such as
|
same problem exists with many other FreeBSD utilities, such as
|
||||||
.B "gpt"
|
\fBgpt\fR, \fBfdisk\fR, and \fBdd\fR.)
|
||||||
,
|
|
||||||
.B "fdisk"
|
|
||||||
, and
|
|
||||||
.B "dd".
|
|
||||||
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
@@ -596,21 +524,19 @@ alignment.
|
|||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
Only ASCII characters are supported in the partition name field. If an
|
Only ASCII characters are supported in the partition name field. If an
|
||||||
existing partition uses non-ASCII UTF-16 characters, they're likely to be
|
existing partition uses non\-ASCII UTF\-16 characters, they're likely to be
|
||||||
corrupted in the 'i' menu option's display; however, they should be
|
corrupted in the 'i' and 'p' menu options' displays; however, they should be
|
||||||
preserved when loading and saving partitions.
|
preserved when loading and saving partitions.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
The program can load only up to 124 logical partitions when converting from
|
The program can load only up to 128 partitions (4 primary partitions and
|
||||||
MBR format. This limit can be raised by changing the #define NUM_LOGICALS
|
124 logical partitions) when converting from MBR format. This limit can
|
||||||
line in the
|
be raised by changing the \fI#define MAX_MBR_PARTS\fR line in the
|
||||||
.IR "mbr.cc"
|
\fImbr.h\fR source code file and recompiling; however, such a change
|
||||||
source code file and recompiling; however, such a change will require using
|
will require using a larger\-than\-normal GPT partition table. (The limit
|
||||||
a larger-than-normal GPT partition table. (The limit of 124 logical
|
of 128 partitions was chosen because that number equals the 128 partitions
|
||||||
partitions was chosen because that number plus the four primary partitions
|
supported by the most common GPT partition table size.)
|
||||||
equals the 128 partitions supported by the most common GPT partition table
|
|
||||||
size.)
|
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
@@ -618,7 +544,8 @@ Converting from MBR format sometimes fails because of insufficient space at
|
|||||||
the start or (more commonly) the end of the disk. Resizing the partition
|
the start or (more commonly) the end of the disk. Resizing the partition
|
||||||
table (using the 's' option in the experts' menu) can sometimes overcome
|
table (using the 's' option in the experts' menu) can sometimes overcome
|
||||||
this problem; however, in extreme cases it may be necessary to resize a
|
this problem; however, in extreme cases it may be necessary to resize a
|
||||||
partition using GNU Parted or a similar tool.
|
partition using GNU Parted or a similar tool prior to conversion with
|
||||||
|
\fBgdisk\fR.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
@@ -636,7 +563,7 @@ partition(s) may need to be deleted.
|
|||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
Because of the highly variable nature of BSD disklabel structures,
|
Because of the highly variable nature of BSD disklabel structures,
|
||||||
conversions from this form may be unreliable -- partitions may be dropped,
|
conversions from this form may be unreliable \-\- partitions may be dropped,
|
||||||
converted in a way that creates overlaps with other partitions, or
|
converted in a way that creates overlaps with other partitions, or
|
||||||
converted with incorrect start or end values. Use this feature with
|
converted with incorrect start or end values. Use this feature with
|
||||||
caution!
|
caution!
|
||||||
@@ -644,21 +571,20 @@ caution!
|
|||||||
.TP
|
.TP
|
||||||
.B *
|
.B *
|
||||||
Booting after converting an MBR or BSD disklabel disk is likely to be
|
Booting after converting an MBR or BSD disklabel disk is likely to be
|
||||||
disrupted. Sometimes re-installing a boot loader will fix the problem, but
|
disrupted. Sometimes re\-installing a boot loader will fix the problem, but
|
||||||
other times you may need to switch boot loaders. Except on EFI-based
|
other times you may need to switch boot loaders. Except on EFI\-based
|
||||||
platforms, Windows through at least Windows 7 RC doesn't support booting
|
platforms, Windows through at least Windows 7 RC doesn't support booting
|
||||||
from GPT disks. Creating a hybrid MBR (using the 'h' option on the experts'
|
from GPT disks. Creating a hybrid MBR (using the 'h' option on the recovery &
|
||||||
menu) or abandoning GPT in favor of MBR may be your only options in this
|
transformation menu) or abandoning GPT in favor of MBR may be your only
|
||||||
case.
|
options in this case.
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
The support for big-endian CPUs (PowerPC, for example) is new, as of version
|
The support for big\-endian CPUs (PowerPC, for example) is new, as of version
|
||||||
0.3.5. I advise using caution on that platform, particularly with the more
|
0.3.5. I advise using caution on that platform, particularly with the more
|
||||||
obscure features of the program.
|
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)
|
||||||
|
|
||||||
Contributors:
|
Contributors:
|
||||||
@@ -668,18 +594,18 @@ Contributors:
|
|||||||
* David Hubbard (david.c.hubbard@gmail.com)
|
* David Hubbard (david.c.hubbard@gmail.com)
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR cfdisk (8),
|
\fBcfdisk (8)\fR,
|
||||||
.BR fdisk (8),
|
\fBfdisk (8)\fR,
|
||||||
.BR mkfs (8),
|
\fBmkfs (8)\fR,
|
||||||
.BR parted (8),
|
\fBparted (8)\fR,
|
||||||
.BR sfdisk (8)
|
\fBsfdisk (8)\fR
|
||||||
|
|
||||||
.IR "http://en.wikipedia.org/wiki/GUID_Partition_Table"
|
\fIhttp://en.wikipedia.org/wiki/GUID_Partition_Table\fR
|
||||||
|
|
||||||
.IR "http://developer.apple.com/technotes/tn2006/tn2166.html"
|
\fIhttp://developer.apple.com/technotes/tn2006/tn2166.html\fR
|
||||||
|
|
||||||
.IR "http://www.rodsbooks.com/gdisk/"
|
\fIhttp://www.rodsbooks.com/gdisk/\fR
|
||||||
|
|
||||||
.SH AVAILABILITY
|
.SH "AVAILABILITY"
|
||||||
The gdisk command is part of the GPT fdisk package and is available from
|
The \fBgdisk\fR command is part of the \fIGPT fdisk\fR package and is
|
||||||
Rod Smith.
|
available from Rod Smith.
|
||||||
|
|||||||
364
gdisk.cc
364
gdisk.cc
@@ -17,25 +17,27 @@
|
|||||||
|
|
||||||
// Function prototypes....
|
// Function prototypes....
|
||||||
// int ReadPartitions(char* filename, struct GPTData* theGPT);
|
// int ReadPartitions(char* filename, struct GPTData* theGPT);
|
||||||
int DoCommand(char* filename, struct GPTData* theGPT);
|
void MainMenu(char* filename, struct GPTData* theGPT);
|
||||||
void ShowCommands(void);
|
void ShowCommands(void);
|
||||||
|
void ExpertsMenu(char* filename, struct GPTData* theGPT);
|
||||||
void ShowExpertCommands(void);
|
void ShowExpertCommands(void);
|
||||||
int ExpertsMenu(char* filename, struct GPTData* theGPT);
|
void RecoveryMenu(char* filename, struct GPTData* theGPT);
|
||||||
|
void ShowRecoveryCommands(void);
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
GPTData theGPT;
|
GPTData theGPT;
|
||||||
int doMore = 1;
|
int doMore = 1;
|
||||||
char* device = NULL;
|
char* device = NULL;
|
||||||
|
|
||||||
printf("GPT fdisk (gdisk) version 0.4.2\n\n");
|
printf("GPT fdisk (gdisk) version 0.5.0\n\n");
|
||||||
|
|
||||||
if (argc == 2) { // basic usage
|
if (argc == 2) { // basic usage
|
||||||
if (SizesOK()) {
|
if (SizesOK()) {
|
||||||
doMore = theGPT.LoadPartitions(argv[1]);
|
doMore = theGPT.LoadPartitions(argv[1]);
|
||||||
while (doMore) {
|
if (doMore) {
|
||||||
doMore = DoCommand(argv[1], &theGPT);
|
MainMenu(argv[1], &theGPT);
|
||||||
} // while
|
} // if (doMore)
|
||||||
} // if
|
} // if (SizesOK())
|
||||||
} else if (argc == 3) { // usage with "-l" option
|
} else if (argc == 3) { // usage with "-l" option
|
||||||
if (SizesOK()) {
|
if (SizesOK()) {
|
||||||
if (strcmp(argv[1], "-l") == 0) {
|
if (strcmp(argv[1], "-l") == 0) {
|
||||||
@@ -55,112 +57,242 @@ int main(int argc, char* argv[]) {
|
|||||||
} // if/else
|
} // if/else
|
||||||
} // main
|
} // main
|
||||||
|
|
||||||
// Accept a command and execute it. Returns 0 if the command includes
|
// Accept a command and execute it. Returns only when the user
|
||||||
// an exit condition (such as a q or w command), 1 if more commands
|
// wants to exit (such as after a 'w' or 'q' command).
|
||||||
// should be processed.
|
void MainMenu(char* filename, struct GPTData* theGPT) {
|
||||||
int DoCommand(char* filename, struct GPTData* theGPT) {
|
char command, line[255], buFile[255];
|
||||||
char command, line[255];
|
int goOn = 1;
|
||||||
int retval = 1;
|
|
||||||
PartTypes typeHelper;
|
PartTypes typeHelper;
|
||||||
uint32_t temp1, temp2;
|
uint32_t temp1, temp2;
|
||||||
|
|
||||||
printf("\nCommand (m for help): ");
|
do {
|
||||||
fgets(line, 255, stdin);
|
printf("\nCommand (? for help): ");
|
||||||
sscanf(line, "%c", &command);
|
fgets(line, 255, stdin);
|
||||||
switch (command) {
|
sscanf(line, "%c", &command);
|
||||||
case 'b': case 'B':
|
switch (command) {
|
||||||
theGPT->XFormDisklabel();
|
case 'b': case 'B':
|
||||||
break;
|
printf("Enter backup filename to save: ");
|
||||||
case 'c': case 'C':
|
fgets(line, 255, stdin);
|
||||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
sscanf(line, "%s", &buFile);
|
||||||
theGPT->SetName(theGPT->GetPartNum());
|
theGPT->SaveGPTBackup(buFile);
|
||||||
else
|
break;
|
||||||
printf("No partitions\n");
|
case 'c': case 'C':
|
||||||
break;
|
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
||||||
case 'd': case 'D':
|
theGPT->SetName(theGPT->GetPartNum());
|
||||||
theGPT->DeletePartition();
|
else
|
||||||
break;
|
printf("No partitions\n");
|
||||||
case 'i': case 'I':
|
break;
|
||||||
theGPT->ShowDetails();
|
case 'd': case 'D':
|
||||||
break;
|
theGPT->DeletePartition();
|
||||||
case 'l': case 'L':
|
break;
|
||||||
typeHelper.ShowTypes();
|
case 'i': case 'I':
|
||||||
break;
|
theGPT->ShowDetails();
|
||||||
case 'n': case 'N':
|
break;
|
||||||
theGPT->CreatePartition();
|
case 'l': case 'L':
|
||||||
break;
|
typeHelper.ShowTypes();
|
||||||
case 'o': case 'O':
|
break;
|
||||||
printf("This option deletes all partitions and creates a new "
|
case 'n': case 'N':
|
||||||
"protective MBR.\nProceed? ");
|
theGPT->CreatePartition();
|
||||||
if (GetYN() == 'Y') {
|
break;
|
||||||
theGPT->ClearGPTData();
|
case 'o': case 'O':
|
||||||
theGPT->MakeProtectiveMBR();
|
printf("This option deletes all partitions and creates a new "
|
||||||
} // if
|
"protective MBR.\nProceed? ");
|
||||||
break;
|
if (GetYN() == 'Y') {
|
||||||
case 'p': case 'P':
|
theGPT->ClearGPTData();
|
||||||
theGPT->DisplayGPTData();
|
theGPT->MakeProtectiveMBR();
|
||||||
break;
|
} // if
|
||||||
case 'q': case 'Q':
|
break;
|
||||||
retval = 0;
|
case 'p': case 'P':
|
||||||
break;
|
theGPT->DisplayGPTData();
|
||||||
case 's': case 'S':
|
break;
|
||||||
theGPT->SortGPT();
|
case 'q': case 'Q':
|
||||||
printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
|
goOn = 0;
|
||||||
break;
|
break;
|
||||||
case 't': case 'T':
|
case 'r': case 'R':
|
||||||
theGPT->ChangePartType();
|
RecoveryMenu(filename, theGPT);
|
||||||
break;
|
goOn = 0;
|
||||||
case 'v': case 'V':
|
break;
|
||||||
if (theGPT->Verify() > 0) { // problems found
|
case 's': case 'S':
|
||||||
printf("You may be able to correct the problems by using options on the experts\n"
|
theGPT->SortGPT();
|
||||||
"menu (press 'x' at the command prompt). Good luck!\n");
|
printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
|
||||||
} // if
|
break;
|
||||||
break;
|
case 't': case 'T':
|
||||||
case 'w': case 'W':
|
theGPT->ChangePartType();
|
||||||
if (theGPT->SaveGPTData() == 1)
|
break;
|
||||||
retval = 0;
|
case 'v': case 'V':
|
||||||
break;
|
if (theGPT->Verify() > 0) { // problems found
|
||||||
case 'x': case 'X':
|
printf("You may be able to correct the problems by using options on the experts\n"
|
||||||
retval = ExpertsMenu(filename, theGPT);
|
"menu (press 'x' at the command prompt). Good luck!\n");
|
||||||
break;
|
} // if
|
||||||
default:
|
break;
|
||||||
ShowCommands();
|
case 'w': case 'W':
|
||||||
break;
|
if (theGPT->SaveGPTData() == 1)
|
||||||
} // switch
|
goOn = 0;
|
||||||
return (retval);
|
break;
|
||||||
} // DoCommand()
|
case 'x': case 'X':
|
||||||
|
ExpertsMenu(filename, theGPT);
|
||||||
|
goOn = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ShowCommands();
|
||||||
|
break;
|
||||||
|
} // switch
|
||||||
|
} while (goOn);
|
||||||
|
} // MainMenu()
|
||||||
|
|
||||||
void ShowCommands(void) {
|
void ShowCommands(void) {
|
||||||
printf("b\tconvert BSD disklabel partitions\n");
|
printf("b\tback up GPT data to a file\n");
|
||||||
printf("c\tchange a partition's name\n");
|
printf("c\tchange a partition's name\n");
|
||||||
printf("d\tdelete a partition\n");
|
printf("d\tdelete a partition\n");
|
||||||
printf("i\tshow detailed information on a partition\n");
|
printf("i\tshow detailed information on a partition\n");
|
||||||
printf("l\tlist available partition types\n");
|
printf("l\tlist known partition types\n");
|
||||||
printf("m\tprint this menu\n");
|
|
||||||
printf("n\tadd a new partition\n");
|
printf("n\tadd a new partition\n");
|
||||||
printf("o\tcreate a new empty GUID partition table (GPT)\n");
|
printf("o\tcreate a new empty GUID partition table (GPT)\n");
|
||||||
printf("p\tprint the partition table\n");
|
printf("p\tprint the partition table\n");
|
||||||
printf("q\tquit without saving changes\n");
|
printf("q\tquit without saving changes\n");
|
||||||
|
printf("r\trecovery and transformation options (experts only)\n");
|
||||||
printf("s\tsort partitions\n");
|
printf("s\tsort partitions\n");
|
||||||
printf("t\tchange a partition's type code\n");
|
printf("t\tchange a partition's type code\n");
|
||||||
printf("v\tverify disk\n");
|
printf("v\tverify disk\n");
|
||||||
printf("w\twrite table to disk and exit\n");
|
printf("w\twrite table to disk and exit\n");
|
||||||
printf("x\textra functionality (experts only)\n");
|
printf("x\textra functionality (experts only)\n");
|
||||||
|
printf("?\tprint this menu\n");
|
||||||
} // ShowCommands()
|
} // ShowCommands()
|
||||||
|
|
||||||
// Accept a command and execute it. Returns 0 if the command includes
|
// Accept a recovery & transformation menu command. Returns only when the user
|
||||||
// an exit condition (such as a q or w command), 1 if more commands
|
// issues an exit command, such as 'w' or 'q'.
|
||||||
// should be processed.
|
void RecoveryMenu(char* filename, struct GPTData* theGPT) {
|
||||||
int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|
||||||
char command, line[255], buFile[255];
|
char command, line[255], buFile[255];
|
||||||
int retval = 1;
|
PartTypes typeHelper;
|
||||||
|
uint32_t temp1;
|
||||||
|
int goOn = 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
printf("\nrecovery/transformation command (? for help): ");
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
sscanf(line, "%c", &command);
|
||||||
|
switch (command) {
|
||||||
|
case 'b': case 'B':
|
||||||
|
theGPT->RebuildMainHeader();
|
||||||
|
break;
|
||||||
|
case 'c': case 'C':
|
||||||
|
printf("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':
|
||||||
|
printf("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':
|
||||||
|
printf("Warning! This will destroy the currently defined partitions! Proceed? ");
|
||||||
|
if (GetYN() == 'Y') {
|
||||||
|
if (theGPT->LoadMBR(filename) == 1) { // successful load
|
||||||
|
theGPT->XFormPartitions();
|
||||||
|
} else {
|
||||||
|
printf("Problem loading MBR! GPT is untouched; regenerating protective MBR!\n");
|
||||||
|
theGPT->MakeProtectiveMBR();
|
||||||
|
} // if/else
|
||||||
|
} // if
|
||||||
|
break;
|
||||||
|
case 'g': case 'G':
|
||||||
|
temp1 = theGPT->XFormToMBR();
|
||||||
|
if (temp1 > 0) {
|
||||||
|
printf("Converted %d partitions. Finalize and exit? ", temp1);
|
||||||
|
if (GetYN() == 'Y') {
|
||||||
|
if (theGPT->DestroyGPT(0) > 0)
|
||||||
|
goOn = 0;
|
||||||
|
} else {
|
||||||
|
theGPT->MakeProtectiveMBR();
|
||||||
|
printf("Note: New protective MBR created.\n");
|
||||||
|
} // if/else
|
||||||
|
} // if
|
||||||
|
break;
|
||||||
|
case 'h': case 'H':
|
||||||
|
theGPT->MakeHybrid();
|
||||||
|
break;
|
||||||
|
case 'i': case 'I':
|
||||||
|
theGPT->ShowDetails();
|
||||||
|
break;
|
||||||
|
case 'l': case 'L':
|
||||||
|
printf("Enter backup filename to load: ");
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
sscanf(line, "%s", &buFile);
|
||||||
|
theGPT->LoadGPTBackup(buFile);
|
||||||
|
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) {
|
||||||
|
printf("b\tuse backup GPT header (rebuilding main)\n");
|
||||||
|
printf("c\tload backup partition table from disk (rebuilding main)\n");
|
||||||
|
printf("d\tuse main GPT header (rebuilding backup)\n");
|
||||||
|
printf("e\tload main partition table from disk (rebuilding backup)\n");
|
||||||
|
printf("f\tload MBR and build fresh GPT from it\n");
|
||||||
|
printf("g\tconvert GPT into MBR and exit\n");
|
||||||
|
printf("h\tmake hybrid MBR\n");
|
||||||
|
printf("i\tshow detailed information on a partition\n");
|
||||||
|
printf("l\tload partition data from a backup file\n");
|
||||||
|
printf("m\treturn to main menu\n");
|
||||||
|
printf("o\tprint protective MBR data\n");
|
||||||
|
printf("p\tprint the partition table\n");
|
||||||
|
printf("q\tquit without saving changes\n");
|
||||||
|
printf("t\ttransform BSD disklabel partition\n");
|
||||||
|
printf("v\tverify disk\n");
|
||||||
|
printf("w\twrite table to disk and exit\n");
|
||||||
|
printf("x\textra functionality (experts only)\n");
|
||||||
|
printf("?\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(char* filename, struct GPTData* theGPT) {
|
||||||
|
char command, line[255];
|
||||||
PartTypes typeHelper;
|
PartTypes typeHelper;
|
||||||
uint32_t pn;
|
uint32_t pn;
|
||||||
uint32_t temp1, temp2;
|
uint32_t temp1, temp2;
|
||||||
int goOn = 1;
|
int goOn = 1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
printf("\nExpert command (m for help): ");
|
printf("\nExpert command (? for help): ");
|
||||||
fgets(line, 255, stdin);
|
fgets(line, 255, stdin);
|
||||||
sscanf(line, "%c", &command);
|
sscanf(line, "%c", &command);
|
||||||
switch (command) {
|
switch (command) {
|
||||||
@@ -170,25 +302,7 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
else
|
else
|
||||||
printf("No partitions\n");
|
printf("No partitions\n");
|
||||||
break;
|
break;
|
||||||
case 'b': case 'B':
|
|
||||||
theGPT->RebuildMainHeader();
|
|
||||||
break;
|
|
||||||
case 'c': case 'C':
|
case 'c': case 'C':
|
||||||
printf("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':
|
|
||||||
printf("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':
|
|
||||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
|
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
|
||||||
pn = theGPT->GetPartNum();
|
pn = theGPT->GetPartNum();
|
||||||
printf("Enter the partition's new unique GUID:\n");
|
printf("Enter the partition's new unique GUID:\n");
|
||||||
@@ -199,23 +313,12 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
printf("Enter the disk's unique GUID:\n");
|
printf("Enter the disk's unique GUID:\n");
|
||||||
theGPT->SetDiskGUID(GetGUID());
|
theGPT->SetDiskGUID(GetGUID());
|
||||||
break;
|
break;
|
||||||
case 'h': case 'H':
|
|
||||||
theGPT->MakeHybrid();
|
|
||||||
break;
|
|
||||||
case 'i': case 'I':
|
case 'i': case 'I':
|
||||||
theGPT->ShowDetails();
|
theGPT->ShowDetails();
|
||||||
break;
|
break;
|
||||||
case 'k': case 'K':
|
case 'm': case 'M':
|
||||||
printf("Enter backup filename to save: ");
|
MainMenu(filename, theGPT);
|
||||||
fgets(line, 255, stdin);
|
goOn = 0;
|
||||||
sscanf(line, "%s", &buFile);
|
|
||||||
theGPT->SaveGPTBackup(buFile);
|
|
||||||
break;
|
|
||||||
case 'l': case 'L':
|
|
||||||
printf("Enter backup filename to load: ");
|
|
||||||
fgets(line, 255, stdin);
|
|
||||||
sscanf(line, "%s", &buFile);
|
|
||||||
theGPT->LoadGPTBackup(buFile);
|
|
||||||
break;
|
break;
|
||||||
case 'n': case 'N':
|
case 'n': case 'N':
|
||||||
theGPT->MakeProtectiveMBR();
|
theGPT->MakeProtectiveMBR();
|
||||||
@@ -227,10 +330,10 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
theGPT->DisplayGPTData();
|
theGPT->DisplayGPTData();
|
||||||
break;
|
break;
|
||||||
case 'q': case 'Q':
|
case 'q': case 'Q':
|
||||||
retval = 0;
|
|
||||||
goOn = 0;
|
goOn = 0;
|
||||||
break;
|
break;
|
||||||
case 'r': case 'R':
|
case 'r': case 'R':
|
||||||
|
RecoveryMenu(filename, theGPT);
|
||||||
goOn = 0;
|
goOn = 0;
|
||||||
break;
|
break;
|
||||||
case 's': case 'S':
|
case 's': case 'S':
|
||||||
@@ -241,14 +344,12 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
break;
|
break;
|
||||||
case 'w': case 'W':
|
case 'w': case 'W':
|
||||||
if (theGPT->SaveGPTData() == 1) {
|
if (theGPT->SaveGPTData() == 1) {
|
||||||
retval = 0;
|
|
||||||
goOn = 0;
|
goOn = 0;
|
||||||
} // if
|
} // if
|
||||||
break;
|
break;
|
||||||
case 'z': case 'Z':
|
case 'z': case 'Z':
|
||||||
if (theGPT->DestroyGPT() == 1) {
|
if (theGPT->DestroyGPT() == 1) {
|
||||||
retval = 0;
|
goOn = 0;
|
||||||
goOn = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -256,29 +357,22 @@ int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
|||||||
break;
|
break;
|
||||||
} // switch
|
} // switch
|
||||||
} while (goOn);
|
} while (goOn);
|
||||||
return (retval);
|
|
||||||
} // ExpertsMenu()
|
} // ExpertsMenu()
|
||||||
|
|
||||||
void ShowExpertCommands(void) {
|
void ShowExpertCommands(void) {
|
||||||
printf("a\tset attributes\n");
|
printf("a\tset attributes\n");
|
||||||
printf("b\tuse backup GPT header (rebuilding main)\n");
|
printf("c\tchange partition GUID\n");
|
||||||
printf("c\tload backup partition table from disk (rebuilding main)\n");
|
|
||||||
printf("d\tuse main GPT header (rebuilding backup)\n");
|
|
||||||
printf("e\tload main partition table from disk (rebuilding backup)\n");
|
|
||||||
printf("f\tchange partition GUID\n");
|
|
||||||
printf("g\tchange disk GUID\n");
|
printf("g\tchange disk GUID\n");
|
||||||
printf("h\tmake hybrid MBR\n");
|
|
||||||
printf("i\tshow detailed information on a partition\n");
|
printf("i\tshow detailed information on a partition\n");
|
||||||
printf("k\tsave partition data to a backup file\n");
|
printf("m\treturn to main menu\n");
|
||||||
printf("l\tload partition data from a backup file\n");
|
|
||||||
printf("m\tprint this menu\n");
|
|
||||||
printf("n\tcreate a new protective MBR\n");
|
printf("n\tcreate a new protective MBR\n");
|
||||||
printf("o\tprint protective MBR data\n");
|
printf("o\tprint protective MBR data\n");
|
||||||
printf("p\tprint the partition table\n");
|
printf("p\tprint the partition table\n");
|
||||||
printf("q\tquit without saving changes\n");
|
printf("q\tquit without saving changes\n");
|
||||||
printf("r\treturn to main menu\n");
|
printf("r\trecovery and transformation options (experts only)\n");
|
||||||
printf("s\tresize partition table\n");
|
printf("s\tresize partition table\n");
|
||||||
printf("v\tverify disk\n");
|
printf("v\tverify disk\n");
|
||||||
printf("w\twrite table to disk and exit\n");
|
printf("w\twrite table to disk and exit\n");
|
||||||
printf("z\tDestroy GPT data structures and exit\n");
|
printf("z\tzap (destroy) GPT data structures and exit\n");
|
||||||
|
printf("?\tprint this menu\n");
|
||||||
} // ShowExpertCommands()
|
} // ShowExpertCommands()
|
||||||
|
|||||||
251
gpt.cc
251
gpt.cc
@@ -112,7 +112,24 @@ int GPTData::Verify(void) {
|
|||||||
"table when you save your partitions.\n");
|
"table when you save your partitions.\n");
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// Now check that critical main and backup GPT entries match
|
// Now check that the main and backup headers both point to themselves....
|
||||||
|
if (mainHeader.currentLBA != 1) {
|
||||||
|
problems++;
|
||||||
|
printf("\nProblem: The main header's self-pointer doesn't point to itself. This problem\n"
|
||||||
|
"is being automatically corrected, but it may be a symptom of more serious\n"
|
||||||
|
"problems. Think carefully before saving changes with 'w' or using this disk.\n");
|
||||||
|
mainHeader.currentLBA = 1;
|
||||||
|
} // if
|
||||||
|
if (secondHeader.currentLBA != (diskSize - UINT64_C(1))) {
|
||||||
|
problems++;
|
||||||
|
printf("\nProblem: The secondary header's self-pointer doesn't point to itself. This\n"
|
||||||
|
"problem is being automatically corrected, but it may be a symptom of more\n"
|
||||||
|
"serious problems. Think carefully before saving changes with 'w' or using this\n"
|
||||||
|
"disk.\n");
|
||||||
|
secondHeader.currentLBA = diskSize - UINT64_C(1);
|
||||||
|
} // if
|
||||||
|
|
||||||
|
// Now check that critical main and backup GPT entries match each other
|
||||||
if (mainHeader.currentLBA != secondHeader.backupLBA) {
|
if (mainHeader.currentLBA != secondHeader.backupLBA) {
|
||||||
problems++;
|
problems++;
|
||||||
printf("\nProblem: main GPT header's current LBA pointer (%llu) doesn't\n"
|
printf("\nProblem: main GPT header's current LBA pointer (%llu) doesn't\n"
|
||||||
@@ -295,34 +312,38 @@ int GPTData::CheckHeaderValidity(void) {
|
|||||||
// Note: Must be called BEFORE byte-order reversal on big-endian
|
// Note: Must be called BEFORE byte-order reversal on big-endian
|
||||||
// systems!
|
// systems!
|
||||||
int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
|
||||||
uint32_t oldCRC, newCRC;
|
uint32_t oldCRC, newCRC, hSize;
|
||||||
|
|
||||||
// Back up old header CRC and then blank it, since it must be 0 for
|
// Back up old header CRC and then blank it, since it must be 0 for
|
||||||
// computation to be valid
|
// computation to be valid
|
||||||
oldCRC = header->headerCRC;
|
oldCRC = header->headerCRC;
|
||||||
if (IsLittleEndian() == 0)
|
|
||||||
ReverseBytes(&oldCRC, 4);
|
|
||||||
header->headerCRC = UINT32_C(0);
|
header->headerCRC = UINT32_C(0);
|
||||||
|
hSize = header->headerSize;
|
||||||
|
|
||||||
|
// If big-endian system, reverse byte order
|
||||||
|
if (IsLittleEndian() == 0) {
|
||||||
|
ReverseBytes(&oldCRC, 4);
|
||||||
|
} // if
|
||||||
|
|
||||||
// Initialize CRC functions...
|
// Initialize CRC functions...
|
||||||
chksum_crc32gentab();
|
chksum_crc32gentab();
|
||||||
|
|
||||||
// Compute CRC, restore original, and return result of comparison
|
// Compute CRC, restore original, and return result of comparison
|
||||||
newCRC = chksum_crc32((unsigned char*) header, HEADER_SIZE);
|
newCRC = chksum_crc32((unsigned char*) header, HEADER_SIZE);
|
||||||
mainHeader.headerCRC = oldCRC;
|
header->headerCRC = oldCRC;
|
||||||
return (oldCRC == newCRC);
|
return (oldCRC == newCRC);
|
||||||
} // GPTData::CheckHeaderCRC()
|
} // GPTData::CheckHeaderCRC()
|
||||||
|
|
||||||
// Recompute all the CRCs. Must be called before saving (but after reversing
|
// Recompute all the CRCs. Must be called before saving (but after reversing
|
||||||
// byte order on big-endian systems) if any changes have been made.
|
// byte order on big-endian systems) if any changes have been made.
|
||||||
void GPTData::RecomputeCRCs(void) {
|
void GPTData::RecomputeCRCs(void) {
|
||||||
uint32_t crc;
|
uint32_t crc, hSize, trueNumParts;
|
||||||
uint32_t trueNumParts;
|
|
||||||
int littleEndian = 1;
|
int littleEndian = 1;
|
||||||
|
|
||||||
// Initialize CRC functions...
|
// Initialize CRC functions...
|
||||||
chksum_crc32gentab();
|
chksum_crc32gentab();
|
||||||
|
|
||||||
|
hSize = mainHeader.headerSize;
|
||||||
littleEndian = IsLittleEndian();
|
littleEndian = IsLittleEndian();
|
||||||
|
|
||||||
// Compute CRC of partition tables & store in main and secondary headers
|
// Compute CRC of partition tables & store in main and secondary headers
|
||||||
@@ -342,11 +363,11 @@ void GPTData::RecomputeCRCs(void) {
|
|||||||
secondHeader.headerCRC = 0;
|
secondHeader.headerCRC = 0;
|
||||||
|
|
||||||
// Compute & store CRCs of main & secondary headers...
|
// Compute & store CRCs of main & secondary headers...
|
||||||
crc = chksum_crc32((unsigned char*) &mainHeader, HEADER_SIZE);
|
crc = chksum_crc32((unsigned char*) &mainHeader, hSize);
|
||||||
if (littleEndian == 0)
|
if (littleEndian == 0)
|
||||||
ReverseBytes(&crc, 4);
|
ReverseBytes(&crc, 4);
|
||||||
mainHeader.headerCRC = crc;
|
mainHeader.headerCRC = crc;
|
||||||
crc = chksum_crc32((unsigned char*) &secondHeader, HEADER_SIZE);
|
crc = chksum_crc32((unsigned char*) &secondHeader, hSize);
|
||||||
if (littleEndian == 0)
|
if (littleEndian == 0)
|
||||||
ReverseBytes(&crc, 4);
|
ReverseBytes(&crc, 4);
|
||||||
secondHeader.headerCRC = crc;
|
secondHeader.headerCRC = crc;
|
||||||
@@ -359,7 +380,7 @@ void GPTData::RebuildMainHeader(void) {
|
|||||||
|
|
||||||
mainHeader.signature = GPT_SIGNATURE;
|
mainHeader.signature = GPT_SIGNATURE;
|
||||||
mainHeader.revision = secondHeader.revision;
|
mainHeader.revision = secondHeader.revision;
|
||||||
mainHeader.headerSize = HEADER_SIZE;
|
mainHeader.headerSize = secondHeader.headerSize;
|
||||||
mainHeader.headerCRC = UINT32_C(0);
|
mainHeader.headerCRC = UINT32_C(0);
|
||||||
mainHeader.reserved = secondHeader.reserved;
|
mainHeader.reserved = secondHeader.reserved;
|
||||||
mainHeader.currentLBA = secondHeader.backupLBA;
|
mainHeader.currentLBA = secondHeader.backupLBA;
|
||||||
@@ -382,7 +403,7 @@ void GPTData::RebuildSecondHeader(void) {
|
|||||||
|
|
||||||
secondHeader.signature = GPT_SIGNATURE;
|
secondHeader.signature = GPT_SIGNATURE;
|
||||||
secondHeader.revision = mainHeader.revision;
|
secondHeader.revision = mainHeader.revision;
|
||||||
secondHeader.headerSize = HEADER_SIZE;
|
secondHeader.headerSize = mainHeader.headerSize;
|
||||||
secondHeader.headerCRC = UINT32_C(0);
|
secondHeader.headerCRC = UINT32_C(0);
|
||||||
secondHeader.reserved = mainHeader.reserved;
|
secondHeader.reserved = mainHeader.reserved;
|
||||||
secondHeader.currentLBA = mainHeader.backupLBA;
|
secondHeader.currentLBA = mainHeader.backupLBA;
|
||||||
@@ -486,12 +507,6 @@ void GPTData::PartitionScan(int fd) {
|
|||||||
printf("It will be destroyed if you continue!\n");
|
printf("It will be destroyed if you continue!\n");
|
||||||
printf("*******************************************************************\n\n\a");
|
printf("*******************************************************************\n\n\a");
|
||||||
} // if
|
} // if
|
||||||
/* if (bsdFound) {
|
|
||||||
printf("\n*************************************************************************\n");
|
|
||||||
printf("This disk appears to contain a BSD disklabel! It will be destroyed if you\n"
|
|
||||||
"continue!\n");
|
|
||||||
printf("*************************************************************************\n\n\a");
|
|
||||||
} // if */
|
|
||||||
} // GPTData::PartitionScan()
|
} // GPTData::PartitionScan()
|
||||||
|
|
||||||
// Read GPT data from a disk.
|
// Read GPT data from a disk.
|
||||||
@@ -703,7 +718,7 @@ void GPTData::LoadSecondTableAsMain(void) {
|
|||||||
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
|
// Writes GPT (and protective MBR) to disk. Returns 1 on successful
|
||||||
// write, 0 if there was a problem.
|
// write, 0 if there was a problem.
|
||||||
int GPTData::SaveGPTData(void) {
|
int GPTData::SaveGPTData(void) {
|
||||||
int allOK = 1, i;
|
int allOK = 1;
|
||||||
char answer, line[256];
|
char answer, line[256];
|
||||||
int fd;
|
int fd;
|
||||||
uint64_t secondTable;
|
uint64_t secondTable;
|
||||||
@@ -856,6 +871,12 @@ int GPTData::SaveGPTBackup(char* filename) {
|
|||||||
ReverseHeaderBytes(&secondHeader);
|
ReverseHeaderBytes(&secondHeader);
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
|
// Recomputing the CRCs is likely to alter them, which could be bad
|
||||||
|
// if the intent is to save a potentially bad GPT for later analysis;
|
||||||
|
// but if we don't do this, we get bogus errors when we load the
|
||||||
|
// backup. I'm favoring misses over false alarms....
|
||||||
|
RecomputeCRCs();
|
||||||
|
|
||||||
// Now write the protective MBR...
|
// Now write the protective MBR...
|
||||||
protectiveMBR.WriteMBRData(fd);
|
protectiveMBR.WriteMBRData(fd);
|
||||||
|
|
||||||
@@ -1021,8 +1042,8 @@ void GPTData::DisplayGPTData(void) {
|
|||||||
uint64_t temp, totalFree;
|
uint64_t temp, totalFree;
|
||||||
|
|
||||||
BytesToSI(diskSize * blockSize, sizeInSI);
|
BytesToSI(diskSize * blockSize, sizeInSI);
|
||||||
printf("Disk %s: %lu sectors, %s\n", device,
|
printf("Disk %s: %llu sectors, %s\n", device,
|
||||||
(unsigned long) diskSize, sizeInSI);
|
(unsigned long long) diskSize, sizeInSI);
|
||||||
printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr));
|
printf("Disk identifier (GUID): %s\n", GUIDToStr(mainHeader.diskGUID, tempStr));
|
||||||
printf("Partition table holds up to %lu entries\n", (unsigned long) mainHeader.numParts);
|
printf("Partition table holds up to %lu entries\n", (unsigned long) mainHeader.numParts);
|
||||||
printf("First usable sector is %lu, last usable sector is %lu\n",
|
printf("First usable sector is %lu, last usable sector is %lu\n",
|
||||||
@@ -1033,7 +1054,7 @@ void GPTData::DisplayGPTData(void) {
|
|||||||
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
|
BytesToSI(totalFree * (uint64_t) blockSize, sizeInSI));
|
||||||
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
|
printf("\nNumber Start (sector) End (sector) Size Code Name\n");
|
||||||
for (i = 0; i < mainHeader.numParts; i++) {
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
partitions[i].ShowSummary(i, blockSize, sizeInSI);
|
partitions[i].ShowSummary(i, blockSize);
|
||||||
} // for
|
} // for
|
||||||
} // GPTData::DisplayGPTData()
|
} // GPTData::DisplayGPTData()
|
||||||
|
|
||||||
@@ -1212,20 +1233,24 @@ void GPTData::SetAttributes(uint32_t partNum) {
|
|||||||
|
|
||||||
// This function destroys the on-disk GPT structures. Returns 1 if the
|
// This function destroys the on-disk GPT structures. Returns 1 if the
|
||||||
// user confirms destruction, 0 if the user aborts.
|
// user confirms destruction, 0 if the user aborts.
|
||||||
int GPTData::DestroyGPT(void) {
|
// If prompt == 0, don't ask user about proceeding and do NOT wipe out
|
||||||
|
// MBR. (Set prompt == 0 when doing a GPT-to-MBR conversion.)
|
||||||
|
int GPTData::DestroyGPT(int prompt) {
|
||||||
int fd, i;
|
int fd, i;
|
||||||
char blankSector[512], goOn;
|
char blankSector[512], goOn = 'Y', blank = 'N';
|
||||||
|
|
||||||
for (i = 0; i < 512; i++) {
|
for (i = 0; i < 512; i++) {
|
||||||
blankSector[i] = '\0';
|
blankSector[i] = '\0';
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
if ((apmFound) || (bsdFound)) {
|
if (((apmFound) || (bsdFound)) && prompt) {
|
||||||
printf("WARNING: APM or BSD disklabel structures detected! This operation could\n"
|
printf("WARNING: APM or BSD disklabel structures detected! This operation could\n"
|
||||||
"damage any APM or BSD partitions on this disk!\n");
|
"damage any APM or BSD partitions on this disk!\n");
|
||||||
} // if APM or BSD
|
} // if APM or BSD
|
||||||
printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
|
if (prompt) {
|
||||||
goOn = GetYN();
|
printf("\a\aAbout to wipe out GPT on %s. Proceed? ", device);
|
||||||
|
goOn = GetYN();
|
||||||
|
} // if
|
||||||
if (goOn == 'Y') {
|
if (goOn == 'Y') {
|
||||||
fd = open(device, O_WRONLY);
|
fd = open(device, O_WRONLY);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@@ -1245,18 +1270,21 @@ int GPTData::DestroyGPT(void) {
|
|||||||
write(fd, blankSector, 512);
|
write(fd, blankSector, 512);
|
||||||
lseek64(fd, secondHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
|
lseek64(fd, secondHeader.currentLBA * 512, SEEK_SET); // seek to GPT header
|
||||||
write(fd, blankSector, 512); // blank it out
|
write(fd, blankSector, 512); // blank it out
|
||||||
printf("Blank out MBR? ");
|
if (prompt) {
|
||||||
if (GetYN() == 'Y') {
|
printf("Blank out MBR? ");
|
||||||
|
blank = GetYN();
|
||||||
|
}// if
|
||||||
|
// Note on below: Touch the MBR only if the user wants it completely
|
||||||
|
// blanked out. Version 0.4.2 deleted the 0xEE partition and re-wrote
|
||||||
|
// the MBR, but this could wipe out a valid MBR that the program
|
||||||
|
// had subsequently discarded (say, if it conflicted with older GPT
|
||||||
|
// structures).
|
||||||
|
if (blank == 'Y') {
|
||||||
lseek64(fd, 0, SEEK_SET);
|
lseek64(fd, 0, SEEK_SET);
|
||||||
write(fd, blankSector, 512); // blank it out
|
write(fd, blankSector, 512); // blank it out
|
||||||
} else { // write current protective MBR, in case it's hybrid....
|
} else {
|
||||||
// find and delete 0xEE partitions in MBR
|
printf("MBR is unchanged. You may need to delete an EFI GPT (0xEE) partition\n"
|
||||||
for (i = 0; i < 4; i++) {
|
"with fdisk or another tool.\n");
|
||||||
if (protectiveMBR.GetType(i) == (uint8_t) 0xEE) {
|
|
||||||
protectiveMBR.DeletePartition(i);
|
|
||||||
} // if
|
|
||||||
} // for
|
|
||||||
protectiveMBR.WriteMBRData(fd);
|
|
||||||
} // if/else
|
} // if/else
|
||||||
DiskSync(fd);
|
DiskSync(fd);
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -1374,8 +1402,8 @@ int GPTData::XFormPartitions(void) {
|
|||||||
ClearGPTData();
|
ClearGPTData();
|
||||||
|
|
||||||
// Convert the smaller of the # of GPT or MBR partitions
|
// Convert the smaller of the # of GPT or MBR partitions
|
||||||
if (mainHeader.numParts > (NUM_LOGICALS + 4))
|
if (mainHeader.numParts > (MAX_MBR_PARTS))
|
||||||
numToConvert = NUM_LOGICALS + 4;
|
numToConvert = MAX_MBR_PARTS;
|
||||||
else
|
else
|
||||||
numToConvert = mainHeader.numParts;
|
numToConvert = mainHeader.numParts;
|
||||||
|
|
||||||
@@ -1467,15 +1495,102 @@ int GPTData::XFormDisklabel(BSDData* disklabel, int startPart) {
|
|||||||
return numDone;
|
return numDone;
|
||||||
} // GPTData::XFormDisklabel(BSDData* disklabel)
|
} // GPTData::XFormDisklabel(BSDData* disklabel)
|
||||||
|
|
||||||
|
// Add one GPT partition to MBR. Used by XFormToMBR() and MakeHybrid()
|
||||||
|
// functions. Returns 1 if operation was successful.
|
||||||
|
int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
|
||||||
|
int allOK = 1, typeCode, bootable;
|
||||||
|
uint64_t length;
|
||||||
|
char line[255];
|
||||||
|
|
||||||
|
if ((mbrPart < 0) || (mbrPart > 3)) {
|
||||||
|
printf("MBR partition %d is out of range; omitting it.\n", mbrPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
if (gptPart >= mainHeader.numParts) {
|
||||||
|
printf("GPT partition %d is out of range; omitting it.\n", gptPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
if (allOK && (partitions[gptPart].GetLastLBA() == UINT64_C(0))) {
|
||||||
|
printf("GPT partition %d is undefined; omitting it.\n", gptPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if
|
||||||
|
if (allOK && (partitions[gptPart].GetFirstLBA() <= UINT32_MAX) &&
|
||||||
|
(partitions[gptPart].GetLengthLBA() <= UINT32_MAX)) {
|
||||||
|
if (partitions[gptPart].GetLastLBA() > UINT32_MAX) {
|
||||||
|
printf("Caution: Partition end point past 32-bit pointer boundary;"
|
||||||
|
" some OSes may\nreact strangely.\n");
|
||||||
|
} // if partition ends past 32-bit (usually 2TiB) boundary
|
||||||
|
do {
|
||||||
|
printf("Enter an MBR hex code (default %02X): ",
|
||||||
|
typeHelper.GUIDToID(partitions[gptPart].GetType()) / 256);
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
sscanf(line, "%x", &typeCode);
|
||||||
|
if (line[0] == '\n')
|
||||||
|
typeCode = partitions[gptPart].GetHexType() / 256;
|
||||||
|
} while ((typeCode <= 0) || (typeCode > 255));
|
||||||
|
printf("Set the bootable flag? ");
|
||||||
|
bootable = (GetYN() == 'Y');
|
||||||
|
length = partitions[gptPart].GetLengthLBA();
|
||||||
|
protectiveMBR.MakePart(mbrPart, (uint32_t) partitions[gptPart].GetFirstLBA(),
|
||||||
|
(uint32_t) length, typeCode, bootable);
|
||||||
|
} else { // partition out of range
|
||||||
|
printf("Partition %d begins beyond the 32-bit pointer limit of MBR "
|
||||||
|
"partitions, or is\n too big; omitting it.\n", gptPart + 1);
|
||||||
|
allOK = 0;
|
||||||
|
} // if/else
|
||||||
|
return allOK;
|
||||||
|
} // GPTData::OnePartToMBR()
|
||||||
|
|
||||||
|
// Convert the GPT to MBR form. This function is necessarily limited; it
|
||||||
|
// handles at most four partitions and creates layouts that ignore CHS
|
||||||
|
// geometries. Returns the number of converted partitions; if this value
|
||||||
|
// is over 0, the calling function should call DestroyGPT() to destroy
|
||||||
|
// the GPT data, and then exit.
|
||||||
|
int GPTData::XFormToMBR(void) {
|
||||||
|
char line[255];
|
||||||
|
int i, j, numParts, numConverted = 0;
|
||||||
|
uint32_t partNums[4];
|
||||||
|
|
||||||
|
// Get the numbers of up to four partitions to add to the
|
||||||
|
// hybrid MBR....
|
||||||
|
numParts = CountParts();
|
||||||
|
printf("Counted %d partitions.\n", numParts);
|
||||||
|
|
||||||
|
// Prepare the MBR for conversion (empty it of existing partitions).
|
||||||
|
protectiveMBR.EmptyMBR(0);
|
||||||
|
protectiveMBR.SetDiskSize(diskSize);
|
||||||
|
|
||||||
|
if (numParts > 4) { // Over four partitions; engage in triage
|
||||||
|
printf("Type from one to four GPT partition numbers, separated by spaces, to be\n"
|
||||||
|
"used in the MBR, in sequence: ");
|
||||||
|
fgets(line, 255, stdin);
|
||||||
|
numParts = sscanf(line, "%d %d %d %d", &partNums[0], &partNums[1],
|
||||||
|
&partNums[2], &partNums[3]);
|
||||||
|
} else { // Four or fewer partitions; convert them all
|
||||||
|
i = j = 0;
|
||||||
|
while ((j < numParts) && (i < mainHeader.numParts)) {
|
||||||
|
if (partitions[i].GetFirstLBA() > 0) { // if GPT part. is defined
|
||||||
|
partNums[j++] = ++i; // flag it for conversion
|
||||||
|
} else i++;
|
||||||
|
} // while
|
||||||
|
} // if/else
|
||||||
|
|
||||||
|
for (i = 0; i < numParts; i++) {
|
||||||
|
j = partNums[i] - 1;
|
||||||
|
printf("\nCreating entry for partition #%d\n", j + 1);
|
||||||
|
numConverted += OnePartToMBR(j, i);
|
||||||
|
} // for
|
||||||
|
return numConverted;
|
||||||
|
} // GPTData::XFormToMBR()
|
||||||
|
|
||||||
// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with
|
// Create a hybrid MBR -- an ugly, funky thing that helps GPT work with
|
||||||
// OSes that don't understand GPT.
|
// OSes that don't understand GPT.
|
||||||
void GPTData::MakeHybrid(void) {
|
void GPTData::MakeHybrid(void) {
|
||||||
uint32_t partNums[3];
|
uint32_t partNums[3];
|
||||||
char line[255];
|
char line[255];
|
||||||
int numParts, i, j, typeCode, bootable, mbrNum;
|
int numParts, numConverted = 0, i, j, typeCode, mbrNum;
|
||||||
uint64_t length;
|
|
||||||
char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe)
|
char fillItUp = 'M'; // fill extra partition entries? (Yes/No/Maybe)
|
||||||
char eeFirst; // Whether EFI GPT (0xEE) partition comes first in table
|
char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
|
||||||
|
|
||||||
printf("\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n"
|
printf("\nWARNING! Hybrid MBRs are flaky and potentially dangerous! If you decide not\n"
|
||||||
"to use one, just hit the Enter key at the below prompt and your MBR\n"
|
"to use one, just hit the Enter key at the below prompt and your MBR\n"
|
||||||
@@ -1500,38 +1615,14 @@ void GPTData::MakeHybrid(void) {
|
|||||||
for (i = 0; i < numParts; i++) {
|
for (i = 0; i < numParts; i++) {
|
||||||
j = partNums[i] - 1;
|
j = partNums[i] - 1;
|
||||||
printf("\nCreating entry for partition #%d\n", j + 1);
|
printf("\nCreating entry for partition #%d\n", j + 1);
|
||||||
if ((j >= 0) && (j < mainHeader.numParts)) {
|
if (eeFirst == 'Y')
|
||||||
if ((partitions[j].GetLastLBA() < UINT32_MAX) &&
|
mbrNum = i + 1;
|
||||||
(partitions[j].GetLastLBA() > UINT64_C(0))) {
|
else
|
||||||
do {
|
mbrNum = i;
|
||||||
printf("Enter an MBR hex code (default %02X): ",
|
numConverted += OnePartToMBR(j, mbrNum);
|
||||||
typeHelper.GUIDToID(partitions[j].GetType()) / 256);
|
|
||||||
fgets(line, 255, stdin);
|
|
||||||
sscanf(line, "%x", &typeCode);
|
|
||||||
if (line[0] == '\n')
|
|
||||||
typeCode = partitions[j].GetHexType() / 256;
|
|
||||||
} while ((typeCode <= 0) || (typeCode > 255));
|
|
||||||
printf("Set the bootable flag? ");
|
|
||||||
bootable = (GetYN() == 'Y');
|
|
||||||
length = partitions[j].GetLengthLBA();
|
|
||||||
if (eeFirst == 'Y')
|
|
||||||
mbrNum = i + 1;
|
|
||||||
else
|
|
||||||
mbrNum = i;
|
|
||||||
protectiveMBR.MakePart(mbrNum, (uint32_t) partitions[j].GetFirstLBA(),
|
|
||||||
(uint32_t) length, typeCode, bootable);
|
|
||||||
protectiveMBR.SetHybrid();
|
|
||||||
} else { // partition out of range
|
|
||||||
printf("Partition %d ends beyond the 2TiB limit of MBR partitions or does not exist;\n"
|
|
||||||
"omitting it.\n",
|
|
||||||
j + 1);
|
|
||||||
} // if/else
|
|
||||||
} else {
|
|
||||||
printf("Partition %d is out of range; omitting it.\n", j + 1);
|
|
||||||
} // if/else
|
|
||||||
} // for
|
} // for
|
||||||
|
|
||||||
if (numParts > 0) { // User opted to create a hybrid MBR....
|
if ((numParts > 0) && (numConverted > 0)) { // User opted to create a hybrid MBR....
|
||||||
// Create EFI protective partition that covers the start of the disk.
|
// Create EFI protective partition that covers the start of the disk.
|
||||||
// If this location (covering the main GPT data structures) is omitted,
|
// If this location (covering the main GPT data structures) is omitted,
|
||||||
// Linux won't find any partitions on the disk. Note that this is
|
// Linux won't find any partitions on the disk. Note that this is
|
||||||
@@ -1544,6 +1635,7 @@ void GPTData::MakeHybrid(void) {
|
|||||||
else
|
else
|
||||||
mbrNum = numParts;
|
mbrNum = numParts;
|
||||||
protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), 0xEE);
|
protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), 0xEE);
|
||||||
|
protectiveMBR.SetHybrid();
|
||||||
|
|
||||||
// ... and for good measure, if there are any partition spaces left,
|
// ... and for good measure, if there are any partition spaces left,
|
||||||
// optionally create another protective EFI partition to cover as much
|
// optionally create another protective EFI partition to cover as much
|
||||||
@@ -1692,7 +1784,7 @@ int GPTData::ClearGPTData(void) {
|
|||||||
// Now initialize a bunch of stuff that's static....
|
// Now initialize a bunch of stuff that's static....
|
||||||
mainHeader.signature = GPT_SIGNATURE;
|
mainHeader.signature = GPT_SIGNATURE;
|
||||||
mainHeader.revision = 0x00010000;
|
mainHeader.revision = 0x00010000;
|
||||||
mainHeader.headerSize = (uint32_t) HEADER_SIZE;
|
mainHeader.headerSize = HEADER_SIZE;
|
||||||
mainHeader.reserved = 0;
|
mainHeader.reserved = 0;
|
||||||
mainHeader.currentLBA = UINT64_C(1);
|
mainHeader.currentLBA = UINT64_C(1);
|
||||||
mainHeader.partitionEntriesLBA = (uint64_t) 2;
|
mainHeader.partitionEntriesLBA = (uint64_t) 2;
|
||||||
@@ -1790,6 +1882,17 @@ int GPTData::GetPartRange(uint32_t *low, uint32_t *high) {
|
|||||||
return numFound;
|
return numFound;
|
||||||
} // GPTData::GetPartRange()
|
} // GPTData::GetPartRange()
|
||||||
|
|
||||||
|
// Returns the number of defined partitions.
|
||||||
|
uint32_t GPTData::CountParts(void) {
|
||||||
|
int i, counted = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < mainHeader.numParts; i++) {
|
||||||
|
if (partitions[i].GetFirstLBA() > 0)
|
||||||
|
counted++;
|
||||||
|
} // for
|
||||||
|
return counted;
|
||||||
|
} // GPTData::CountParts()
|
||||||
|
|
||||||
/****************************************************
|
/****************************************************
|
||||||
* *
|
* *
|
||||||
* Functions that return data about disk free space *
|
* Functions that return data about disk free space *
|
||||||
@@ -2017,8 +2120,8 @@ int SizesOK(void) {
|
|||||||
fprintf(stderr, "MBRRecord is %d bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord));
|
fprintf(stderr, "MBRRecord is %d bytes, should be 16 bytes; aborting!\n", sizeof(MBRRecord));
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
if (sizeof(struct EBRRecord) != 512) {
|
if (sizeof(struct TempMBR) != 512) {
|
||||||
fprintf(stderr, "EBRRecord is %d bytes, should be 512 bytes; aborting!\n", sizeof(EBRRecord));
|
fprintf(stderr, "TempMBR is %d bytes, should be 512 bytes; aborting!\n", sizeof(TempMBR));
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
} // if
|
} // if
|
||||||
if (sizeof(struct GPTHeader) != 512) {
|
if (sizeof(struct GPTHeader) != 512) {
|
||||||
|
|||||||
10
gpt.h
10
gpt.h
@@ -67,7 +67,6 @@ protected:
|
|||||||
int secondPartsCrcOk;
|
int secondPartsCrcOk;
|
||||||
int apmFound; // set to 1 if APM detected
|
int apmFound; // set to 1 if APM detected
|
||||||
int bsdFound; // set to 1 if BSD disklabel detected in MBR
|
int bsdFound; // set to 1 if BSD disklabel detected in MBR
|
||||||
// uint32_t units; // display units, in multiples of sectors
|
|
||||||
PartTypes typeHelper;
|
PartTypes typeHelper;
|
||||||
public:
|
public:
|
||||||
// Basic necessary functions....
|
// Basic necessary functions....
|
||||||
@@ -87,6 +86,7 @@ public:
|
|||||||
int FindOverlaps(void);
|
int FindOverlaps(void);
|
||||||
|
|
||||||
// Load or save data from/to disk
|
// Load or save data from/to disk
|
||||||
|
int LoadMBR(char* f) {return protectiveMBR.ReadMBRData(f);}
|
||||||
void PartitionScan(int fd);
|
void PartitionScan(int fd);
|
||||||
int LoadPartitions(char* deviceFilename);
|
int LoadPartitions(char* deviceFilename);
|
||||||
int ForceLoadGPTData(int fd);
|
int ForceLoadGPTData(int fd);
|
||||||
@@ -111,13 +111,15 @@ public:
|
|||||||
void DeletePartition(void);
|
void DeletePartition(void);
|
||||||
void ChangePartType(void);
|
void ChangePartType(void);
|
||||||
void SetAttributes(uint32_t partNum);
|
void SetAttributes(uint32_t partNum);
|
||||||
int DestroyGPT(void); // Returns 1 if user proceeds
|
int DestroyGPT(int prompt = 1); // Returns 1 if user proceeds
|
||||||
|
|
||||||
// Convert to GPT from other formats (may require user interaction)
|
// Convert between GPT and other formats (may require user interaction)
|
||||||
WhichToUse UseWhichPartitions(void);
|
WhichToUse UseWhichPartitions(void);
|
||||||
int XFormPartitions(void);
|
int XFormPartitions(void);
|
||||||
int XFormDisklabel(int OnGptPart = -1);
|
int XFormDisklabel(int OnGptPart = -1);
|
||||||
int XFormDisklabel(BSDData* disklabel, int startPart);
|
int XFormDisklabel(BSDData* disklabel, int startPart);
|
||||||
|
int OnePartToMBR(uint32_t gptPart, int mbrPart); // add one partition to MBR. Returns 1 if successful
|
||||||
|
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
|
||||||
void MakeHybrid(void);
|
void MakeHybrid(void);
|
||||||
|
|
||||||
// Adjust GPT structures WITHOUT user interaction...
|
// Adjust GPT structures WITHOUT user interaction...
|
||||||
@@ -139,6 +141,8 @@ public:
|
|||||||
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
|
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
|
||||||
uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
|
uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
|
||||||
mainHeader.sizeOfPartitionEntries) / blockSize;}
|
mainHeader.sizeOfPartitionEntries) / blockSize;}
|
||||||
|
uint32_t CountParts(void);
|
||||||
|
|
||||||
|
|
||||||
// Find information about free space
|
// Find information about free space
|
||||||
uint64_t FindFirstAvailable(uint64_t start = 0);
|
uint64_t FindFirstAvailable(uint64_t start = 0);
|
||||||
|
|||||||
16
gptpart.cc
16
gptpart.cc
@@ -9,8 +9,8 @@
|
|||||||
// Copyright: See COPYING file that comes with this distribution
|
// Copyright: See COPYING file that comes with this distribution
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
||||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
|
||||||
|
|
||||||
#define __STDC_LIMIT_MACROS
|
#define __STDC_LIMIT_MACROS
|
||||||
#define __STDC_CONSTANT_MACROS
|
#define __STDC_CONSTANT_MACROS
|
||||||
@@ -25,6 +25,10 @@ using namespace std;
|
|||||||
PartTypes GPTPart::typeHelper;
|
PartTypes GPTPart::typeHelper;
|
||||||
|
|
||||||
GPTPart::GPTPart(void) {
|
GPTPart::GPTPart(void) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NAME_SIZE; i++)
|
||||||
|
name[i] = '\0';
|
||||||
} // Default constructor
|
} // Default constructor
|
||||||
|
|
||||||
GPTPart::~GPTPart(void) {
|
GPTPart::~GPTPart(void) {
|
||||||
@@ -128,16 +132,16 @@ void GPTPart::ReversePartBytes(void) {
|
|||||||
} // GPTPart::ReverseBytes()
|
} // GPTPart::ReverseBytes()
|
||||||
|
|
||||||
// Display summary information; does nothing if the partition is empty.
|
// Display summary information; does nothing if the partition is empty.
|
||||||
void GPTPart::ShowSummary(int i, uint32_t blockSize, char* sizeInSI) {
|
void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
|
||||||
int j;
|
char sizeInSI[255];
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
if (firstLBA != 0) {
|
if (firstLBA != 0) {
|
||||||
BytesToSI(blockSize * (lastLBA - firstLBA + 1), sizeInSI);
|
BytesToSI(blockSize * (lastLBA - firstLBA + 1), sizeInSI);
|
||||||
printf("%4d %14lu %14lu", i + 1, (unsigned long) firstLBA,
|
printf("%4d %14lu %14lu", partNum + 1, (unsigned long) firstLBA,
|
||||||
(unsigned long) lastLBA);
|
(unsigned long) lastLBA);
|
||||||
printf(" %-10s %04X ", sizeInSI,
|
printf(" %-10s %04X ", sizeInSI,
|
||||||
typeHelper.GUIDToID(partitionType));
|
typeHelper.GUIDToID(partitionType));
|
||||||
j = 0;
|
|
||||||
while ((name[j] != '\0') && (j < 44)) {
|
while ((name[j] != '\0') && (j < 44)) {
|
||||||
printf("%c", name[j]);
|
printf("%c", name[j]);
|
||||||
j += 2;
|
j += 2;
|
||||||
|
|||||||
16
gptpart.h
16
gptpart.h
@@ -9,8 +9,8 @@
|
|||||||
// Copyright: See COPYING file that comes with this distribution
|
// Copyright: See COPYING file that comes with this distribution
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
||||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
|
||||||
|
|
||||||
#ifndef __GPTPART_H
|
#ifndef __GPTPART_H
|
||||||
#define __GPTPART_H
|
#define __GPTPART_H
|
||||||
@@ -23,11 +23,11 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
/*****************************************
|
/****************************************
|
||||||
* *
|
* *
|
||||||
* GUIDPart class and related structures *
|
* GPTPart class and related structures *
|
||||||
* *
|
* *
|
||||||
*****************************************/
|
****************************************/
|
||||||
|
|
||||||
class GPTPart {
|
class GPTPart {
|
||||||
protected:
|
protected:
|
||||||
@@ -73,7 +73,7 @@ class GPTPart {
|
|||||||
|
|
||||||
// Additional functions
|
// Additional functions
|
||||||
GPTPart & operator=(const GPTPart & orig);
|
GPTPart & operator=(const GPTPart & orig);
|
||||||
void ShowSummary(int i, uint32_t blockSize, char* sizeInSI); // display summary information (1-line)
|
void ShowSummary(int partNum, uint32_t blockSize); // display summary information (1-line)
|
||||||
void ShowDetails(uint32_t blockSize); // display detailed information (multi-line)
|
void ShowDetails(uint32_t blockSize); // display detailed information (multi-line)
|
||||||
void BlankPartition(void); // empty partition of data
|
void BlankPartition(void); // empty partition of data
|
||||||
int DoTheyOverlap(GPTPart* other); // returns 1 if there's overlap
|
int DoTheyOverlap(GPTPart* other); // returns 1 if there's overlap
|
||||||
|
|||||||
568
mbr.cc
568
mbr.cc
@@ -1,7 +1,7 @@
|
|||||||
/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
|
/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
|
||||||
data. */
|
data. */
|
||||||
|
|
||||||
/* By Rod Smith, January to February, 2009 */
|
/* Initial coding by Rod Smith, January to February, 2009 */
|
||||||
|
|
||||||
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
|
||||||
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
|
||||||
@@ -35,6 +35,8 @@ MBRData::MBRData(void) {
|
|||||||
strcpy(device, "");
|
strcpy(device, "");
|
||||||
state = invalid;
|
state = invalid;
|
||||||
srand((unsigned int) time(NULL));
|
srand((unsigned int) time(NULL));
|
||||||
|
numHeads = MAX_HEADS;
|
||||||
|
numSecspTrack = MAX_SECSPERTRACK;
|
||||||
EmptyMBR();
|
EmptyMBR();
|
||||||
} // MBRData default constructor
|
} // MBRData default constructor
|
||||||
|
|
||||||
@@ -43,6 +45,8 @@ MBRData::MBRData(char *filename) {
|
|||||||
diskSize = 0;
|
diskSize = 0;
|
||||||
strcpy(device, filename);
|
strcpy(device, filename);
|
||||||
state = invalid;
|
state = invalid;
|
||||||
|
numHeads = MAX_HEADS;
|
||||||
|
numSecspTrack = MAX_SECSPERTRACK;
|
||||||
|
|
||||||
srand((unsigned int) time(NULL));
|
srand((unsigned int) time(NULL));
|
||||||
// Try to read the specified partition table, but if it fails....
|
// Try to read the specified partition table, but if it fails....
|
||||||
@@ -55,51 +59,11 @@ MBRData::MBRData(char *filename) {
|
|||||||
MBRData::~MBRData(void) {
|
MBRData::~MBRData(void) {
|
||||||
} // MBRData destructor
|
} // MBRData destructor
|
||||||
|
|
||||||
// Empty all data. Meant mainly for calling by constructors, but it's also
|
/**********************
|
||||||
// used by the hybrid MBR functions in the GPTData class.
|
* *
|
||||||
void MBRData::EmptyMBR(int clearBootloader) {
|
* Disk I/O functions *
|
||||||
int i;
|
* *
|
||||||
|
**********************/
|
||||||
// Zero out the boot loader section, the disk signature, and the
|
|
||||||
// 2-byte nulls area only if requested to do so. (This is the
|
|
||||||
// default.)
|
|
||||||
if (clearBootloader == 1) {
|
|
||||||
for (i = 0; i < 440; i++)
|
|
||||||
code[i] = 0;
|
|
||||||
diskSignature = (uint32_t) rand();
|
|
||||||
nulls = 0;
|
|
||||||
} // if
|
|
||||||
|
|
||||||
// Blank out the partitions
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
partitions[i].status = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].partitionType = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].firstLBA = UINT32_C(0);
|
|
||||||
partitions[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
MBRSignature = MBR_SIGNATURE;
|
|
||||||
|
|
||||||
blockSize = SECTOR_SIZE;
|
|
||||||
diskSize = 0;
|
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
|
||||||
logicals[i].status = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].partitionType = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].firstLBA = UINT32_C(0);
|
|
||||||
logicals[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
} // MBRData::EmptyMBR()
|
|
||||||
|
|
||||||
// Read data from MBR. Returns 1 if read was successful (even if the
|
// Read data from MBR. Returns 1 if read was successful (even if the
|
||||||
// data isn't a valid MBR), 0 if the read failed.
|
// data isn't a valid MBR), 0 if the read failed.
|
||||||
@@ -120,25 +84,18 @@ int MBRData::ReadMBRData(char* deviceFilename) {
|
|||||||
return allOK;
|
return allOK;
|
||||||
} // MBRData::ReadMBRData(char* deviceFilename)
|
} // MBRData::ReadMBRData(char* deviceFilename)
|
||||||
|
|
||||||
// Read data from MBR.
|
// Read data from MBR. If checkBlockSize == 1 (the default), the block
|
||||||
|
// size is checked; otherwise it's set to the default (512 bytes).
|
||||||
|
// Note that any extended partition(s) present will be explicitly stored
|
||||||
|
// in the partitions[] array, along with their contained partitions; the
|
||||||
|
// extended container partition(s) should be ignored by other functions.
|
||||||
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
||||||
int allOK = 1, i, j, maxLogicals = 0;
|
int allOK = 1, i, j, logicalNum;
|
||||||
int err;
|
int err;
|
||||||
TempMBR tempMBR;
|
TempMBR tempMBR;
|
||||||
|
|
||||||
// Clear logical partition array
|
// Empty existing MBR data, including the logical partitions...
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
EmptyMBR(0);
|
||||||
logicals[i].status = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].partitionType = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].firstLBA = UINT32_C(0);
|
|
||||||
logicals[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
err = lseek64(fd, 0, SEEK_SET);
|
err = lseek64(fd, 0, SEEK_SET);
|
||||||
err = read(fd, &tempMBR, 512);
|
err = read(fd, &tempMBR, 512);
|
||||||
@@ -154,8 +111,8 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
|||||||
for (j = 0; j < 3; j++) {
|
for (j = 0; j < 3; j++) {
|
||||||
partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
|
partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
|
||||||
partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
|
partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
|
||||||
} // for j...
|
} // for j... (reading parts of CHS geometry)
|
||||||
} // for i...
|
} // for i... (reading all four partitions)
|
||||||
MBRSignature = tempMBR.MBRSignature;
|
MBRSignature = tempMBR.MBRSignature;
|
||||||
|
|
||||||
// Reverse the byte order, if necessary
|
// Reverse the byte order, if necessary
|
||||||
@@ -180,21 +137,16 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
|||||||
// Find block size
|
// Find block size
|
||||||
if (checkBlockSize) {
|
if (checkBlockSize) {
|
||||||
blockSize = GetBlockSize(fd);
|
blockSize = GetBlockSize(fd);
|
||||||
// if ((blockSize = GetBlockSize(fd)) == -1) {
|
|
||||||
// blockSize = SECTOR_SIZE;
|
|
||||||
// printf("Unable to determine sector size; assuming %lu bytes!\n",
|
|
||||||
// (unsigned long) SECTOR_SIZE);
|
|
||||||
// } // if
|
|
||||||
} // if (checkBlockSize)
|
} // if (checkBlockSize)
|
||||||
|
|
||||||
// Load logical partition data, if any is found....
|
// Load logical partition data, if any is found....
|
||||||
if (allOK) {
|
if (allOK) {
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
|
if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
|
||||||
|| (partitions[i].partitionType == 0x85)) {
|
|| (partitions[i].partitionType == 0x85)) {
|
||||||
// Found it, so call a recursive algorithm to load everything from them....
|
// Found it, so call a recursive algorithm to load everything from them....
|
||||||
maxLogicals = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), maxLogicals);
|
logicalNum = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), 4);
|
||||||
if ((maxLogicals < 0) || (maxLogicals > NUM_LOGICALS)) {
|
if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
|
||||||
allOK = 0;
|
allOK = 0;
|
||||||
fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
|
fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
|
||||||
} // if maxLogicals valid
|
} // if maxLogicals valid
|
||||||
@@ -224,26 +176,70 @@ void MBRData::ReadMBRData(int fd, int checkBlockSize) {
|
|||||||
(partitions[i].partitionType != UINT8_C(0x00)))
|
(partitions[i].partitionType != UINT8_C(0x00)))
|
||||||
state = hybrid;
|
state = hybrid;
|
||||||
} // for
|
} // for
|
||||||
} // if hybrid
|
} // if (hybrid detection code)
|
||||||
|
|
||||||
/* // Tell the user what the MBR state is...
|
|
||||||
switch (state) {
|
|
||||||
case invalid:
|
|
||||||
printf("Information: MBR appears to be empty or invalid.\n");
|
|
||||||
break;
|
|
||||||
case gpt:
|
|
||||||
printf("Information: MBR holds GPT placeholder partitions.\n");
|
|
||||||
break;
|
|
||||||
case hybrid:
|
|
||||||
printf("Information: MBR holds hybrid GPT/MBR data.\n");
|
|
||||||
break;
|
|
||||||
case mbr:
|
|
||||||
printf("Information: MBR data appears to be valid.\n");
|
|
||||||
break;
|
|
||||||
} // switch */
|
|
||||||
} // MBRData::ReadMBRData(int fd)
|
} // MBRData::ReadMBRData(int fd)
|
||||||
|
|
||||||
// Write the MBR data to the default defined device.
|
// This is a recursive function to read all the logical partitions, following the
|
||||||
|
// logical partition linked list from the disk and storing the basic data in the
|
||||||
|
// partitions[] array. Returns last index to partitions[] used, or -1 if there was
|
||||||
|
// a problem.
|
||||||
|
// Parameters:
|
||||||
|
// fd = file descriptor
|
||||||
|
// extendedStart = LBA of the start of the extended partition
|
||||||
|
// diskOffset = LBA offset WITHIN the extended partition of the one to be read
|
||||||
|
// partNum = location in partitions[] array to store retrieved data
|
||||||
|
int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
|
||||||
|
uint32_t diskOffset, int partNum) {
|
||||||
|
struct TempMBR ebr;
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
// Check for a valid partition number. Note that partitions MAY be read into
|
||||||
|
// the area normally used by primary partitions, although the only calling
|
||||||
|
// function as of GPT fdisk version 0.5.0 doesn't do so.
|
||||||
|
if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
|
||||||
|
offset = (off_t) (extendedStart + diskOffset) * blockSize;
|
||||||
|
if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
|
||||||
|
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
|
||||||
|
partNum = -1;
|
||||||
|
}
|
||||||
|
if (read(fd, &ebr, 512) != 512) { // Load the data....
|
||||||
|
fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
|
||||||
|
(unsigned long) offset);
|
||||||
|
partNum = -1;
|
||||||
|
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
|
||||||
|
ReverseBytes(&ebr.MBRSignature, 2);
|
||||||
|
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
|
||||||
|
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
|
||||||
|
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
|
||||||
|
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
|
||||||
|
} // if/else/if
|
||||||
|
|
||||||
|
if (ebr.MBRSignature != MBR_SIGNATURE) {
|
||||||
|
partNum = -1;
|
||||||
|
fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
|
||||||
|
(unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
|
||||||
|
} // if
|
||||||
|
|
||||||
|
// Copy over the basic data....
|
||||||
|
partitions[partNum].status = ebr.partitions[0].status;
|
||||||
|
partitions[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
|
||||||
|
partitions[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
|
||||||
|
partitions[partNum].partitionType = ebr.partitions[0].partitionType;
|
||||||
|
|
||||||
|
// Find the next partition (if there is one) and recurse....
|
||||||
|
if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 4) &&
|
||||||
|
(partNum < (MAX_MBR_PARTS - 1))) {
|
||||||
|
partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
|
||||||
|
partNum + 1);
|
||||||
|
} else {
|
||||||
|
partNum++;
|
||||||
|
} // if another partition
|
||||||
|
} // Not enough space for all the logicals (or previous error encountered)
|
||||||
|
return (partNum);
|
||||||
|
} // MBRData::ReadLogicalPart()
|
||||||
|
|
||||||
|
// Write the MBR data to the default defined device. Note that this writes
|
||||||
|
// ONLY the MBR itself, not the logical partition data.
|
||||||
int MBRData::WriteMBRData(void) {
|
int MBRData::WriteMBRData(void) {
|
||||||
int allOK = 1, fd;
|
int allOK = 1, fd;
|
||||||
|
|
||||||
@@ -295,12 +291,6 @@ void MBRData::WriteMBRData(int fd) {
|
|||||||
lseek64(fd, 0, SEEK_SET);
|
lseek64(fd, 0, SEEK_SET);
|
||||||
write(fd, &tempMBR, 512);
|
write(fd, &tempMBR, 512);
|
||||||
|
|
||||||
/* write(fd, code, 440);
|
|
||||||
write(fd, &diskSignature, 4);
|
|
||||||
write(fd, &nulls, 2);
|
|
||||||
write(fd, partitions, 64);
|
|
||||||
write(fd, &MBRSignature, 2); */
|
|
||||||
|
|
||||||
// Reverse the byte order back, if necessary
|
// Reverse the byte order back, if necessary
|
||||||
if (IsLittleEndian() == 0) {
|
if (IsLittleEndian() == 0) {
|
||||||
ReverseBytes(&diskSignature, 4);
|
ReverseBytes(&diskSignature, 4);
|
||||||
@@ -313,56 +303,11 @@ void MBRData::WriteMBRData(int fd) {
|
|||||||
}// if
|
}// if
|
||||||
} // MBRData::WriteMBRData(int fd)
|
} // MBRData::WriteMBRData(int fd)
|
||||||
|
|
||||||
// This is a recursive function to read all the logical partitions, following the
|
/********************************************
|
||||||
// logical partition linked list from the disk and storing the basic data in the
|
* *
|
||||||
// logicals[] array. Returns last index to logicals[] uses, or -1 if there was a
|
* Functions that display data for the user *
|
||||||
// problem
|
* *
|
||||||
int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
|
********************************************/
|
||||||
uint32_t diskOffset, int partNum) {
|
|
||||||
struct EBRRecord ebr;
|
|
||||||
off_t offset;
|
|
||||||
|
|
||||||
if ((partNum < NUM_LOGICALS) && (partNum >= 0)) {
|
|
||||||
offset = (off_t) (extendedStart + diskOffset) * blockSize;
|
|
||||||
if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
|
|
||||||
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
|
|
||||||
partNum = -1;
|
|
||||||
}
|
|
||||||
if (read(fd, &ebr, 512) != 512) { // Load the data....
|
|
||||||
fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
|
|
||||||
(unsigned long) offset);
|
|
||||||
partNum = -1;
|
|
||||||
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
|
|
||||||
ReverseBytes(&ebr.MBRSignature, 2);
|
|
||||||
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
|
|
||||||
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
|
|
||||||
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
|
|
||||||
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
|
|
||||||
} // if/else/if
|
|
||||||
|
|
||||||
if (ebr.MBRSignature != MBR_SIGNATURE) {
|
|
||||||
partNum = -1;
|
|
||||||
fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
|
|
||||||
(unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
|
|
||||||
} // if
|
|
||||||
|
|
||||||
// Copy over the basic data....
|
|
||||||
logicals[partNum].status = ebr.partitions[0].status;
|
|
||||||
logicals[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
|
|
||||||
logicals[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
|
|
||||||
logicals[partNum].partitionType = ebr.partitions[0].partitionType;
|
|
||||||
|
|
||||||
// Find the next partition (if there is one) and recurse....
|
|
||||||
if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 0) &&
|
|
||||||
(partNum < (NUM_LOGICALS - 1))) {
|
|
||||||
partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
|
|
||||||
partNum + 1);
|
|
||||||
} else {
|
|
||||||
partNum++;
|
|
||||||
} // if another partition
|
|
||||||
} // Not enough space for all the logicals (or previous error encountered)
|
|
||||||
return (partNum);
|
|
||||||
} // MBRData::ReadLogicalPart()
|
|
||||||
|
|
||||||
// Show the MBR data to the user....
|
// Show the MBR data to the user....
|
||||||
void MBRData::DisplayMBRData(void) {
|
void MBRData::DisplayMBRData(void) {
|
||||||
@@ -373,10 +318,10 @@ void MBRData::DisplayMBRData(void) {
|
|||||||
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
|
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
|
||||||
printf("MBR partitions:\n");
|
printf("MBR partitions:\n");
|
||||||
printf("Number\t Boot\t Start (sector)\t Length (sectors)\tType\n");
|
printf("Number\t Boot\t Start (sector)\t Length (sectors)\tType\n");
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < MAX_MBR_PARTS; i++) {
|
||||||
if (partitions[i].lengthLBA != 0) {
|
if (partitions[i].lengthLBA != 0) {
|
||||||
if (partitions[i].status && 0x80) // it's bootable
|
if (partitions[i].status && 0x80) // it's bootable
|
||||||
bootCode = '*';
|
bootCode = '*';
|
||||||
else
|
else
|
||||||
bootCode = ' ';
|
bootCode = ' ';
|
||||||
printf("%4d\t %c\t%13lu\t%15lu \t0x%02X\n", i + 1, bootCode,
|
printf("%4d\t %c\t%13lu\t%15lu \t0x%02X\n", i + 1, bootCode,
|
||||||
@@ -384,31 +329,144 @@ void MBRData::DisplayMBRData(void) {
|
|||||||
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
|
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
|
printf("\nDisk size is %llu sectors (%s)\n", (unsigned long long) diskSize,
|
||||||
// Now display logical partition data....
|
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
|
||||||
if (logicals[i].lengthLBA != 0) {
|
|
||||||
printf("%4d\t%13lu\t%15lu \t0x%02X\n", i + 5, (unsigned long) logicals[i].firstLBA,
|
|
||||||
(unsigned long) logicals[i].lengthLBA, logicals[i].partitionType);
|
|
||||||
} // if
|
|
||||||
} // for
|
|
||||||
printf("\nDisk size is %lu sectors (%s)\n", (unsigned long) diskSize,
|
|
||||||
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
|
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
|
||||||
} // MBRData::DisplayMBRData()
|
} // MBRData::DisplayMBRData()
|
||||||
|
|
||||||
|
// Displays the state, as a word, on stdout. Used for debugging & to
|
||||||
|
// tell the user about the MBR state when the program launches....
|
||||||
|
void MBRData::ShowState(void) {
|
||||||
|
switch (state) {
|
||||||
|
case invalid:
|
||||||
|
printf(" MBR: not present\n");
|
||||||
|
break;
|
||||||
|
case gpt:
|
||||||
|
printf(" MBR: protective\n");
|
||||||
|
break;
|
||||||
|
case hybrid:
|
||||||
|
printf(" MBR: hybrid\n");
|
||||||
|
break;
|
||||||
|
case mbr:
|
||||||
|
printf(" MBR: MBR only\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("\a MBR: unknown -- bug!\n");
|
||||||
|
break;
|
||||||
|
} // switch
|
||||||
|
} // MBRData::ShowState()
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* *
|
||||||
|
* Functions that set or get disk metadata (CHS geometry, disk size, *
|
||||||
|
* etc.) *
|
||||||
|
* *
|
||||||
|
*********************************************************************/
|
||||||
|
|
||||||
|
// Sets the CHS geometry. CHS geometry is used by LBAtoCHS() function.
|
||||||
|
// Note that this only sets the heads and sectors; the number of
|
||||||
|
// cylinders is determined by these values and the disk size.
|
||||||
|
void MBRData::SetCHSGeom(uint32_t h, uint32_t s) {
|
||||||
|
if ((h <= MAX_HEADS) && (s <= MAX_SECSPERTRACK)) {
|
||||||
|
numHeads = h;
|
||||||
|
numSecspTrack = s;
|
||||||
|
} else {
|
||||||
|
printf("Warning! Attempt to set invalid CHS geometry!\n");
|
||||||
|
} // if/else
|
||||||
|
} // MBRData::SetCHSGeom()
|
||||||
|
|
||||||
|
// Converts 64-bit LBA value to MBR-style CHS value. Returns 1 if conversion
|
||||||
|
// was within the range that can be expressed by CHS (including 0, for an
|
||||||
|
// empty partition), 0 if the value is outside that range, and -1 if chs is
|
||||||
|
// invalid.
|
||||||
|
int MBRData::LBAtoCHS(uint64_t lba, uint8_t * chs) {
|
||||||
|
uint64_t cylinder, head, sector; // all numbered from 0
|
||||||
|
uint64_t remainder;
|
||||||
|
int retval = 1;
|
||||||
|
int done = 0;
|
||||||
|
|
||||||
|
if (chs != NULL) {
|
||||||
|
// Special case: In case of 0 LBA value, zero out CHS values....
|
||||||
|
if (lba == 0) {
|
||||||
|
chs[0] = chs[1] = chs[2] = UINT8_C(0);
|
||||||
|
done = 1;
|
||||||
|
} // if
|
||||||
|
// If LBA value is too large for CHS, max out CHS values....
|
||||||
|
if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
|
||||||
|
chs[0] = 254;
|
||||||
|
chs[1] = chs[2] = 255;
|
||||||
|
done = 1;
|
||||||
|
retval = 0;
|
||||||
|
} // if
|
||||||
|
// If neither of the above applies, compute CHS values....
|
||||||
|
if (!done) {
|
||||||
|
cylinder = lba / (uint64_t) (numHeads * numSecspTrack);
|
||||||
|
remainder = lba - (cylinder * numHeads * numSecspTrack);
|
||||||
|
head = remainder / numSecspTrack;
|
||||||
|
remainder -= head * numSecspTrack;
|
||||||
|
sector = remainder;
|
||||||
|
if (head < numHeads)
|
||||||
|
chs[0] = head;
|
||||||
|
else
|
||||||
|
retval = 0;
|
||||||
|
if (sector < numSecspTrack) {
|
||||||
|
chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
|
||||||
|
chs[2] = (uint8_t) (cylinder & UINT64_C(0xFF));
|
||||||
|
} else {
|
||||||
|
retval = 0;
|
||||||
|
} // if/else
|
||||||
|
} // if value is expressible and non-0
|
||||||
|
} else { // Invalid (NULL) chs pointer
|
||||||
|
retval = -1;
|
||||||
|
} // if CHS pointer valid
|
||||||
|
return (retval);
|
||||||
|
} // MBRData::LBAtoCHS()
|
||||||
|
|
||||||
|
/*****************************************************
|
||||||
|
* *
|
||||||
|
* Functions to create, delete, or change partitions *
|
||||||
|
* *
|
||||||
|
*****************************************************/
|
||||||
|
|
||||||
|
// Empty all data. Meant mainly for calling by constructors, but it's also
|
||||||
|
// used by the hybrid MBR functions in the GPTData class.
|
||||||
|
void MBRData::EmptyMBR(int clearBootloader) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Zero out the boot loader section, the disk signature, and the
|
||||||
|
// 2-byte nulls area only if requested to do so. (This is the
|
||||||
|
// default.)
|
||||||
|
if (clearBootloader == 1) {
|
||||||
|
for (i = 0; i < 440; i++)
|
||||||
|
code[i] = 0;
|
||||||
|
diskSignature = (uint32_t) rand();
|
||||||
|
nulls = 0;
|
||||||
|
} // if
|
||||||
|
|
||||||
|
// Blank out the partitions
|
||||||
|
for (i = 0; i < MAX_MBR_PARTS; i++) {
|
||||||
|
partitions[i].status = UINT8_C(0);
|
||||||
|
partitions[i].firstSector[0] = UINT8_C(0);
|
||||||
|
partitions[i].firstSector[1] = UINT8_C(0);
|
||||||
|
partitions[i].firstSector[2] = UINT8_C(0);
|
||||||
|
partitions[i].partitionType = UINT8_C(0);
|
||||||
|
partitions[i].lastSector[0] = UINT8_C(0);
|
||||||
|
partitions[i].lastSector[1] = UINT8_C(0);
|
||||||
|
partitions[i].lastSector[2] = UINT8_C(0);
|
||||||
|
partitions[i].firstLBA = UINT32_C(0);
|
||||||
|
partitions[i].lengthLBA = UINT32_C(0);
|
||||||
|
} // for
|
||||||
|
MBRSignature = MBR_SIGNATURE;
|
||||||
|
} // MBRData::EmptyMBR()
|
||||||
|
|
||||||
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
|
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
|
||||||
void MBRData::MakeProtectiveMBR(int clearBoot) {
|
void MBRData::MakeProtectiveMBR(int clearBoot) {
|
||||||
int i;
|
|
||||||
|
EmptyMBR(clearBoot);
|
||||||
|
|
||||||
// Initialize variables
|
// Initialize variables
|
||||||
nulls = 0;
|
nulls = 0;
|
||||||
MBRSignature = MBR_SIGNATURE;
|
MBRSignature = MBR_SIGNATURE;
|
||||||
|
|
||||||
if (clearBoot > 0) {
|
|
||||||
for (i = 0; i < 440; i++)
|
|
||||||
code[i] = (uint8_t) 0;
|
|
||||||
} // if
|
|
||||||
|
|
||||||
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
|
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
|
||||||
|
|
||||||
// Write CHS data. This maxes out the use of the disk, as much as
|
// Write CHS data. This maxes out the use of the disk, as much as
|
||||||
@@ -427,44 +485,43 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
|
|||||||
partitions[0].partitionType = UINT8_C(0xEE);
|
partitions[0].partitionType = UINT8_C(0xEE);
|
||||||
partitions[0].firstLBA = UINT32_C(1);
|
partitions[0].firstLBA = UINT32_C(1);
|
||||||
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
|
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
|
||||||
partitions[0].lengthLBA = diskSize - 1;
|
partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1);
|
||||||
} else { // disk is too big to represent, so fake it...
|
} else { // disk is too big to represent, so fake it...
|
||||||
partitions[0].lengthLBA = UINT32_MAX;
|
partitions[0].lengthLBA = UINT32_MAX;
|
||||||
} // if/else
|
} // if/else
|
||||||
|
|
||||||
// Zero out three unused primary partitions...
|
|
||||||
for (i = 1; i < 4; i++) {
|
|
||||||
partitions[i].status = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].firstSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].partitionType = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[0] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[1] = UINT8_C(0);
|
|
||||||
partitions[i].lastSector[2] = UINT8_C(0);
|
|
||||||
partitions[i].firstLBA = UINT32_C(0);
|
|
||||||
partitions[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
// Zero out all the logical partitions. Not necessary for data
|
|
||||||
// integrity on write, but eliminates stray entries if user wants
|
|
||||||
// to view the MBR after converting the disk
|
|
||||||
for (i = 0; i < NUM_LOGICALS; i++) {
|
|
||||||
logicals[i].status = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].firstSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].partitionType = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[0] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[1] = UINT8_C(0);
|
|
||||||
logicals[i].lastSector[2] = UINT8_C(0);
|
|
||||||
logicals[i].firstLBA = UINT32_C(0);
|
|
||||||
logicals[i].lengthLBA = UINT32_C(0);
|
|
||||||
} // for
|
|
||||||
|
|
||||||
state = gpt;
|
state = gpt;
|
||||||
} // MBRData::MakeProtectiveMBR()
|
} // MBRData::MakeProtectiveMBR()
|
||||||
|
|
||||||
|
// Create a partition of the specified number, starting LBA, and
|
||||||
|
// length. This function does *NO* error checking, so it's possible
|
||||||
|
// to seriously screw up a partition table using this function!
|
||||||
|
// Note: This function should NOT be used to create the 0xEE partition
|
||||||
|
// in a conventional GPT configuration, since that partition has
|
||||||
|
// specific size requirements that this function won't handle. It may
|
||||||
|
// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
|
||||||
|
// since those toss the rulebook away anyhow....
|
||||||
|
void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
|
||||||
|
int bootable) {
|
||||||
|
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
|
||||||
|
partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
|
||||||
|
partitions[num].firstSector[0] = UINT8_C(0);
|
||||||
|
partitions[num].firstSector[1] = UINT8_C(0);
|
||||||
|
partitions[num].firstSector[2] = UINT8_C(0);
|
||||||
|
partitions[num].partitionType = (uint8_t) type;
|
||||||
|
partitions[num].lastSector[0] = UINT8_C(0);
|
||||||
|
partitions[num].lastSector[1] = UINT8_C(0);
|
||||||
|
partitions[num].lastSector[2] = UINT8_C(0);
|
||||||
|
partitions[num].firstLBA = start;
|
||||||
|
partitions[num].lengthLBA = length;
|
||||||
|
// If this is a "real" partition, set its CHS geometry
|
||||||
|
if (length > 0) {
|
||||||
|
LBAtoCHS((uint64_t) start, partitions[num].firstSector);
|
||||||
|
LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector);
|
||||||
|
} // if (length > 0)
|
||||||
|
} // if valid partition number
|
||||||
|
} // MBRData::MakePart()
|
||||||
|
|
||||||
// Create a partition that fills the most available space. Returns
|
// Create a partition that fills the most available space. Returns
|
||||||
// 1 if partition was created, 0 otherwise. Intended for use in
|
// 1 if partition was created, 0 otherwise. Intended for use in
|
||||||
// creating hybrid MBRs.
|
// creating hybrid MBRs.
|
||||||
@@ -482,11 +539,11 @@ int MBRData::MakeBiggestPart(int i, int type) {
|
|||||||
if (firstBlock != UINT32_C(0)) { // something's free...
|
if (firstBlock != UINT32_C(0)) { // something's free...
|
||||||
lastBlock = FindLastInFree(firstBlock);
|
lastBlock = FindLastInFree(firstBlock);
|
||||||
segmentSize = lastBlock - firstBlock + UINT32_C(1);
|
segmentSize = lastBlock - firstBlock + UINT32_C(1);
|
||||||
if (segmentSize > selectedSize) {
|
if (segmentSize > selectedSize) {
|
||||||
selectedSize = segmentSize;
|
selectedSize = segmentSize;
|
||||||
selectedSegment = firstBlock;
|
selectedSegment = firstBlock;
|
||||||
} // if
|
} // if
|
||||||
start = lastBlock + 1;
|
start = lastBlock + 1;
|
||||||
} // if
|
} // if
|
||||||
} while (firstBlock != 0);
|
} while (firstBlock != 0);
|
||||||
if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
|
if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
|
||||||
@@ -517,18 +574,19 @@ void MBRData::DeletePartition(int i) {
|
|||||||
// Used to help keep GPT & hybrid MBR partitions in sync....
|
// Used to help keep GPT & hybrid MBR partitions in sync....
|
||||||
int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
|
int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
|
||||||
uint32_t start32, length32;
|
uint32_t start32, length32;
|
||||||
int i, j, deleted = 0;
|
int i, deleted = 0;
|
||||||
|
|
||||||
if ((state == hybrid) && (start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
|
if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
|
||||||
start32 = (uint32_t) start64;
|
start32 = (uint32_t) start64;
|
||||||
length32 = (uint32_t) length64;
|
length32 = (uint32_t) length64;
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < MAX_MBR_PARTS; i++) {
|
||||||
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
|
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
|
||||||
(partitions[i].partitionType != 0xEE)) {
|
(partitions[i].partitionType != 0xEE)) {
|
||||||
DeletePartition(i);
|
DeletePartition(i);
|
||||||
OptimizeEESize();
|
if (state == hybrid)
|
||||||
|
OptimizeEESize();
|
||||||
deleted = 1;
|
deleted = 1;
|
||||||
} // if (match found)
|
} // if (match found)
|
||||||
} // for i (partition scan)
|
} // for i (partition scan)
|
||||||
} // if (hybrid & GPT partition < 2TiB)
|
} // if (hybrid & GPT partition < 2TiB)
|
||||||
return deleted;
|
return deleted;
|
||||||
@@ -554,74 +612,24 @@ void MBRData::OptimizeEESize(void) {
|
|||||||
partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
|
partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
|
||||||
} // if free space after
|
} // if free space after
|
||||||
} // if partition is 0xEE
|
} // if partition is 0xEE
|
||||||
if (typeFlag == 0) { // No non-hybrid partitions found
|
|
||||||
MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
|
|
||||||
} // if
|
|
||||||
} // for partition loop
|
} // for partition loop
|
||||||
|
if (typeFlag == 0) { // No non-hybrid partitions found
|
||||||
|
MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
|
||||||
|
} // if
|
||||||
} // MBRData::OptimizeEESize()
|
} // MBRData::OptimizeEESize()
|
||||||
|
|
||||||
// Return a pointer to a primary or logical partition, or NULL if
|
/****************************************
|
||||||
// the partition is out of range....
|
* *
|
||||||
struct MBRRecord* MBRData::GetPartition(int i) {
|
* Functions to find data on free space *
|
||||||
MBRRecord* thePart = NULL;
|
* *
|
||||||
|
****************************************/
|
||||||
if ((i >= 0) && (i < 4)) { // primary partition
|
|
||||||
thePart = &partitions[i];
|
|
||||||
} // if
|
|
||||||
if ((i >= 4) && (i < (NUM_LOGICALS + 4))) {
|
|
||||||
thePart = &logicals[i - 4];
|
|
||||||
} // if
|
|
||||||
return thePart;
|
|
||||||
} // GetPartition()
|
|
||||||
|
|
||||||
// Displays the state, as a word, on stdout. Used for debugging & to
|
|
||||||
// tell the user about the MBR state when the program launches....
|
|
||||||
void MBRData::ShowState(void) {
|
|
||||||
switch (state) {
|
|
||||||
case invalid:
|
|
||||||
printf(" MBR: not present\n");
|
|
||||||
break;
|
|
||||||
case gpt:
|
|
||||||
printf(" MBR: protective\n");
|
|
||||||
break;
|
|
||||||
case hybrid:
|
|
||||||
printf(" MBR: hybrid\n");
|
|
||||||
break;
|
|
||||||
case mbr:
|
|
||||||
printf(" MBR: MBR only\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("\a MBR: unknown -- bug!\n");
|
|
||||||
break;
|
|
||||||
} // switch
|
|
||||||
} // MBRData::ShowState()
|
|
||||||
|
|
||||||
// Create a primary partition of the specified number, starting LBA,
|
|
||||||
// and length. This function does *NO* error checking, so it's possible
|
|
||||||
// to seriously screw up a partition table using this function! It's
|
|
||||||
// intended as a way to create a hybrid MBR, which is a pretty funky
|
|
||||||
// setup to begin with....
|
|
||||||
void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
|
|
||||||
int bootable) {
|
|
||||||
|
|
||||||
partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
|
|
||||||
partitions[num].firstSector[0] = UINT8_C(0);
|
|
||||||
partitions[num].firstSector[1] = UINT8_C(0);
|
|
||||||
partitions[num].firstSector[2] = UINT8_C(0);
|
|
||||||
partitions[num].partitionType = (uint8_t) type;
|
|
||||||
partitions[num].lastSector[0] = UINT8_C(0);
|
|
||||||
partitions[num].lastSector[1] = UINT8_C(0);
|
|
||||||
partitions[num].lastSector[2] = UINT8_C(0);
|
|
||||||
partitions[num].firstLBA = start;
|
|
||||||
partitions[num].lengthLBA = length;
|
|
||||||
} // MakePart()
|
|
||||||
|
|
||||||
// Finds the first free space on the disk from start onward; returns 0
|
// Finds the first free space on the disk from start onward; returns 0
|
||||||
// if none available....
|
// if none available....
|
||||||
uint32_t MBRData::FindFirstAvailable(uint32_t start) {
|
uint32_t MBRData::FindFirstAvailable(uint32_t start) {
|
||||||
uint32_t first;
|
uint32_t first;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
int firstMoved = 0;
|
int firstMoved;
|
||||||
|
|
||||||
first = start;
|
first = start;
|
||||||
|
|
||||||
@@ -638,7 +646,7 @@ uint32_t MBRData::FindFirstAvailable(uint32_t start) {
|
|||||||
(first < (partitions[i].firstLBA + partitions[i].lengthLBA))) {
|
(first < (partitions[i].firstLBA + partitions[i].lengthLBA))) {
|
||||||
first = partitions[i].firstLBA + partitions[i].lengthLBA;
|
first = partitions[i].firstLBA + partitions[i].lengthLBA;
|
||||||
firstMoved = 1;
|
firstMoved = 1;
|
||||||
} // if
|
} // if
|
||||||
} // for
|
} // for
|
||||||
} while (firstMoved == 1);
|
} while (firstMoved == 1);
|
||||||
if (first >= diskSize)
|
if (first >= diskSize)
|
||||||
@@ -651,7 +659,7 @@ uint32_t MBRData::FindLastInFree(uint32_t start) {
|
|||||||
uint32_t nearestStart;
|
uint32_t nearestStart;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
if (diskSize <= UINT32_MAX)
|
if ((diskSize <= UINT32_MAX) && (diskSize > 0))
|
||||||
nearestStart = diskSize - 1;
|
nearestStart = diskSize - 1;
|
||||||
else
|
else
|
||||||
nearestStart = UINT32_MAX - 1;
|
nearestStart = UINT32_MAX - 1;
|
||||||
@@ -688,6 +696,8 @@ int MBRData::IsFree(uint32_t sector) {
|
|||||||
|
|
||||||
for (i = 0; i < 4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
first = partitions[i].firstLBA;
|
first = partitions[i].firstLBA;
|
||||||
|
// Note: Weird two-line thing to avoid subtracting 1 from a 0 value
|
||||||
|
// for an unsigned int....
|
||||||
last = first + partitions[i].lengthLBA;
|
last = first + partitions[i].lengthLBA;
|
||||||
if (last > 0) last--;
|
if (last > 0) last--;
|
||||||
if ((first <= sector) && (last >= sector))
|
if ((first <= sector) && (last >= sector))
|
||||||
@@ -696,6 +706,12 @@ int MBRData::IsFree(uint32_t sector) {
|
|||||||
return isFree;
|
return isFree;
|
||||||
} // MBRData::IsFree()
|
} // MBRData::IsFree()
|
||||||
|
|
||||||
|
/******************************************************
|
||||||
|
* *
|
||||||
|
* Functions that extract data on specific partitions *
|
||||||
|
* *
|
||||||
|
******************************************************/
|
||||||
|
|
||||||
uint8_t MBRData::GetStatus(int i) {
|
uint8_t MBRData::GetStatus(int i) {
|
||||||
MBRRecord* thePart;
|
MBRRecord* thePart;
|
||||||
uint8_t retval;
|
uint8_t retval;
|
||||||
@@ -729,7 +745,7 @@ uint32_t MBRData::GetFirstSector(int i) {
|
|||||||
retval = thePart->firstLBA;
|
retval = thePart->firstLBA;
|
||||||
} else
|
} else
|
||||||
retval = UINT32_C(0);
|
retval = UINT32_C(0);
|
||||||
return retval;
|
return retval;
|
||||||
} // MBRData::GetFirstSector()
|
} // MBRData::GetFirstSector()
|
||||||
|
|
||||||
uint32_t MBRData::GetLength(int i) {
|
uint32_t MBRData::GetLength(int i) {
|
||||||
@@ -741,7 +757,7 @@ uint32_t MBRData::GetLength(int i) {
|
|||||||
retval = thePart->lengthLBA;
|
retval = thePart->lengthLBA;
|
||||||
} else
|
} else
|
||||||
retval = UINT32_C(0);
|
retval = UINT32_C(0);
|
||||||
return retval;
|
return retval;
|
||||||
} // MBRData::GetLength()
|
} // MBRData::GetLength()
|
||||||
|
|
||||||
// Return the MBR data as a GPT partition....
|
// Return the MBR data as a GPT partition....
|
||||||
@@ -772,7 +788,23 @@ GPTPart MBRData::AsGPT(int i) {
|
|||||||
newPart.SetUniqueGUID(1);
|
newPart.SetUniqueGUID(1);
|
||||||
newPart.SetAttributes(0);
|
newPart.SetAttributes(0);
|
||||||
newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
|
newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
|
||||||
} // if
|
} // if not extended, protective, or non-existent
|
||||||
} // if
|
} // if (origPart != NULL)
|
||||||
return newPart;
|
return newPart;
|
||||||
} // MBRData::AsGPT()
|
} // MBRData::AsGPT()
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* *
|
||||||
|
* Protected functions *
|
||||||
|
* *
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
// Return a pointer to a primary or logical partition, or NULL if
|
||||||
|
// the partition is out of range....
|
||||||
|
struct MBRRecord* MBRData::GetPartition(int i) {
|
||||||
|
MBRRecord* thePart = NULL;
|
||||||
|
|
||||||
|
if ((i >= 0) && (i < MAX_MBR_PARTS))
|
||||||
|
thePart = &partitions[i];
|
||||||
|
return thePart;
|
||||||
|
} // GetPartition()
|
||||||
|
|||||||
62
mbr.h
62
mbr.h
@@ -12,9 +12,12 @@
|
|||||||
#define __MBRSTRUCTS
|
#define __MBRSTRUCTS
|
||||||
|
|
||||||
#define MBR_SIGNATURE UINT16_C(0xAA55)
|
#define MBR_SIGNATURE UINT16_C(0xAA55)
|
||||||
|
#define MAX_HEADS 255 /* numbered 0 - 254 */
|
||||||
|
#define MAX_SECSPERTRACK 63 /* numbered 1 - 63 */
|
||||||
|
#define MAX_CYLINDERS 1024 /* numbered 0 - 1023 */
|
||||||
|
|
||||||
// Maximum number of logical partitions supported
|
// Maximum number of MBR partitions
|
||||||
#define NUM_LOGICALS 124
|
#define MAX_MBR_PARTS 128
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -36,9 +39,10 @@ struct MBRRecord {
|
|||||||
uint32_t lengthLBA;
|
uint32_t lengthLBA;
|
||||||
}; // struct MBRRecord
|
}; // struct MBRRecord
|
||||||
|
|
||||||
// Create a 512-byte data structure into which the MBR can be loaded in one
|
// A 512-byte data structure into which the MBR can be loaded in one
|
||||||
// go, for the benefit of FreeBSD which seems to flake out when loading
|
// go, for the benefit of FreeBSD which seems to flake out when loading
|
||||||
// from block devices in multiples other than the block size....
|
// from block devices in multiples other than the block size.
|
||||||
|
// Also used when loading logical partitions.
|
||||||
struct TempMBR {
|
struct TempMBR {
|
||||||
uint8_t code[440];
|
uint8_t code[440];
|
||||||
uint32_t diskSignature;
|
uint32_t diskSignature;
|
||||||
@@ -47,20 +51,6 @@ struct TempMBR {
|
|||||||
uint16_t MBRSignature;
|
uint16_t MBRSignature;
|
||||||
}; // struct TempMBR
|
}; // struct TempMBR
|
||||||
|
|
||||||
// Extended Boot Record (EBR) data, used to hold one logical partition's
|
|
||||||
// data within an extended partition. Includes pointer to next record for
|
|
||||||
// in-memory linked-list access. This is similar to MBRData, but with a
|
|
||||||
// few tweaks....
|
|
||||||
struct EBRRecord {
|
|
||||||
uint8_t code[446]; // generally 0s (and we don't care if they aren't)
|
|
||||||
// First partition entry defines partition; second points to next
|
|
||||||
// entry in on-disk linked list; remaining two are unused. Note that
|
|
||||||
// addresses are relative to the extended partition, not to the disk
|
|
||||||
// as a whole.
|
|
||||||
struct MBRRecord partitions[4];
|
|
||||||
uint16_t MBRSignature;
|
|
||||||
}; // struct EBRRecord
|
|
||||||
|
|
||||||
// Possible states of the MBR
|
// Possible states of the MBR
|
||||||
enum MBRValidity {invalid, gpt, hybrid, mbr};
|
enum MBRValidity {invalid, gpt, hybrid, mbr};
|
||||||
|
|
||||||
@@ -70,45 +60,55 @@ protected:
|
|||||||
uint8_t code[440];
|
uint8_t code[440];
|
||||||
uint32_t diskSignature;
|
uint32_t diskSignature;
|
||||||
uint16_t nulls;
|
uint16_t nulls;
|
||||||
struct MBRRecord partitions[4];
|
// MAX_MBR_PARTS defaults to 128. This array holds both the primary and
|
||||||
|
// the logical partitions, to simplify data retrieval for GPT conversions.
|
||||||
|
struct MBRRecord partitions[MAX_MBR_PARTS];
|
||||||
uint16_t MBRSignature;
|
uint16_t MBRSignature;
|
||||||
|
|
||||||
// Above are basic MBR data; now add more stuff....
|
// Above are basic MBR data; now add more stuff....
|
||||||
uint32_t blockSize; // block size (usually 512)
|
uint32_t blockSize; // block size (usually 512)
|
||||||
uint64_t diskSize; // size in blocks
|
uint64_t diskSize; // size in blocks
|
||||||
|
uint64_t numHeads; // number of heads, in CHS scheme
|
||||||
|
uint64_t numSecspTrack; // number of sectors per track, in CHS scheme
|
||||||
char device[256];
|
char device[256];
|
||||||
// Now an array of partitions for the logicals, in array form (easier
|
|
||||||
// than a linked list, and good enough for the GPT itself, so....)
|
|
||||||
struct MBRRecord logicals[NUM_LOGICALS];
|
|
||||||
MBRValidity state;
|
MBRValidity state;
|
||||||
struct MBRRecord* GetPartition(int i); // Return primary or logical partition
|
struct MBRRecord* GetPartition(int i); // Return primary or logical partition
|
||||||
public:
|
public:
|
||||||
MBRData(void);
|
MBRData(void);
|
||||||
MBRData(char* deviceFilename);
|
MBRData(char* deviceFilename);
|
||||||
~MBRData(void);
|
~MBRData(void);
|
||||||
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
|
|
||||||
void EmptyMBR(int clearBootloader = 1);
|
// File I/O functions...
|
||||||
void SetDiskSize(uint64_t ds) {diskSize = ds;}
|
|
||||||
int ReadMBRData(char* deviceFilename);
|
int ReadMBRData(char* deviceFilename);
|
||||||
void ReadMBRData(int fd, int checkBlockSize = 1);
|
void ReadMBRData(int fd, int checkBlockSize = 1);
|
||||||
|
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
||||||
|
int partNum);
|
||||||
int WriteMBRData(void);
|
int WriteMBRData(void);
|
||||||
void WriteMBRData(int fd);
|
void WriteMBRData(int fd);
|
||||||
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
// ReadLogicalPart() returns last partition # read to logicals[] array,
|
||||||
// or -1 if there was a problem....
|
// or -1 if there was a problem....
|
||||||
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
|
||||||
int partNum);
|
// Display data for user...
|
||||||
void DisplayMBRData(void);
|
void DisplayMBRData(void);
|
||||||
void MakeProtectiveMBR(int clearBoot = 0);
|
|
||||||
MBRValidity GetValidity(void) {return state;}
|
|
||||||
void ShowValidity(void);
|
|
||||||
void ShowState(void);
|
void ShowState(void);
|
||||||
|
|
||||||
|
// Functions that set or get disk metadata (size, CHS geometry, etc.)
|
||||||
|
void SetDiskSize(uint64_t ds) {diskSize = ds;}
|
||||||
|
MBRValidity GetValidity(void) {return state;}
|
||||||
|
void SetHybrid(void) {state = hybrid;} // Set hybrid flag
|
||||||
|
void SetCHSGeom(uint32_t h, uint32_t s);
|
||||||
|
int LBAtoCHS(uint64_t lba, uint8_t * chs); // Convert LBA to CHS
|
||||||
|
|
||||||
|
// Functions to create, delete, or change partitions
|
||||||
|
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
|
||||||
|
void EmptyMBR(int clearBootloader = 1);
|
||||||
|
void MakeProtectiveMBR(int clearBoot = 0);
|
||||||
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
|
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
|
||||||
int bootable = 0);
|
int bootable = 0);
|
||||||
int MakeBiggestPart(int i, int type); // Make partition filling most space
|
int MakeBiggestPart(int i, int type); // Make partition filling most space
|
||||||
void DeletePartition(int i);
|
void DeletePartition(int i);
|
||||||
int DeleteByLocation(uint64_t start64, uint64_t length64);
|
int DeleteByLocation(uint64_t start64, uint64_t length64);
|
||||||
void OptimizeEESize(void);
|
void OptimizeEESize(void);
|
||||||
void SetHybrid(void) {state = hybrid;} // Set hybrid flag
|
|
||||||
|
|
||||||
// Functions to find information on free space....
|
// Functions to find information on free space....
|
||||||
uint32_t FindFirstAvailable(uint32_t start = 1);
|
uint32_t FindFirstAvailable(uint32_t start = 1);
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ PartTypes::PartTypes(void) {
|
|||||||
"EFI System"); // EFI System (parted marks Linux boot
|
"EFI System"); // EFI System (parted marks Linux boot
|
||||||
// partitions like this)
|
// partitions like this)
|
||||||
AddType(0xEF01, UINT64_C(0x11d333e7024dee41), UINT64_C(0x9FF381C70800699d),
|
AddType(0xEF01, UINT64_C(0x11d333e7024dee41), UINT64_C(0x9FF381C70800699d),
|
||||||
"MBR partition scheme"); // Whatever that is (from Wikipedia)
|
"MBR partition scheme"); // Used to nest an MBR table on a GPT disk
|
||||||
AddType(0xEF02, UINT64_C(0x6E6F644921686148), UINT64_C(0x4946456465654E74),
|
AddType(0xEF02, UINT64_C(0x6E6F644921686148), UINT64_C(0x4946456465654E74),
|
||||||
"BIOS boot partition"); //
|
"BIOS boot partition"); //
|
||||||
|
|
||||||
|
|||||||
22
support.cc
22
support.cc
@@ -205,7 +205,9 @@ int GetBlockSize(int fd) {
|
|||||||
result = SECTOR_SIZE;
|
result = SECTOR_SIZE;
|
||||||
// ENOTTY = inappropriate ioctl; probably being called on a disk image
|
// ENOTTY = inappropriate ioctl; probably being called on a disk image
|
||||||
// file, so don't display the warning message....
|
// file, so don't display the warning message....
|
||||||
if (errno != ENOTTY) {
|
// 32-bit code returns EINVAL, I don't know why. I know I'm treading on
|
||||||
|
// thin ice here, but it should be OK in all but very weird cases....
|
||||||
|
if ((errno != ENOTTY) && (errno != EINVAL)) {
|
||||||
printf("\aError %d when determining sector size! Setting sector size to %d\n",
|
printf("\aError %d when determining sector size! Setting sector size to %d\n",
|
||||||
errno, SECTOR_SIZE);
|
errno, SECTOR_SIZE);
|
||||||
} // if
|
} // if
|
||||||
@@ -434,8 +436,9 @@ void DiskSync(int fd) {
|
|||||||
uint64_t disksize(int fd, int *err) {
|
uint64_t disksize(int fd, int *err) {
|
||||||
long sz; // Do not delete; needed for Linux
|
long sz; // Do not delete; needed for Linux
|
||||||
long long b; // Do not delete; needed for Linux
|
long long b; // Do not delete; needed for Linux
|
||||||
uint64_t sectors = 0, bytes = 0; // size in sectors & bytes
|
uint64_t sectors = 0; // size in sectors
|
||||||
struct stat st;
|
off_t bytes = 0; // size in bytes
|
||||||
|
struct stat64 st;
|
||||||
|
|
||||||
// Note to self: I recall testing a simplified version of
|
// Note to self: I recall testing a simplified version of
|
||||||
// this code, similar to what's in the __APPLE__ block,
|
// this code, similar to what's in the __APPLE__ block,
|
||||||
@@ -462,17 +465,6 @@ uint64_t disksize(int fd, int *err) {
|
|||||||
sectors = (b >> 9);
|
sectors = (b >> 9);
|
||||||
} // if
|
} // if
|
||||||
|
|
||||||
// if (*err) {
|
|
||||||
// sz = 0;
|
|
||||||
// if (errno != EFBIG)
|
|
||||||
// return sz;
|
|
||||||
// }
|
|
||||||
// *err = ioctl(fd, BLKGETSIZE64, &b);
|
|
||||||
// if (*err || b == 0 || b == sz)
|
|
||||||
// sectors = sz;
|
|
||||||
// else
|
|
||||||
// sectors = (b >> 9);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -480,7 +472,7 @@ uint64_t disksize(int fd, int *err) {
|
|||||||
// so let's assume it's a regular file (a QEMU image, dd backup, or
|
// so let's assume it's a regular file (a QEMU image, dd backup, or
|
||||||
// what have you) and see what stat() gives us....
|
// what have you) and see what stat() gives us....
|
||||||
if (sectors == 0) {
|
if (sectors == 0) {
|
||||||
if (fstat(fd, &st) == 0) {
|
if (fstat64(fd, &st) == 0) {
|
||||||
bytes = (uint64_t) st.st_size;
|
bytes = (uint64_t) st.st_size;
|
||||||
if ((bytes % UINT64_C(512)) != 0)
|
if ((bytes % UINT64_C(512)) != 0)
|
||||||
fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
|
fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!"
|
||||||
|
|||||||
14
support.h
14
support.h
@@ -4,6 +4,10 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef __GPTSUPPORT
|
||||||
|
#define __GPTSUPPORT
|
||||||
|
|
||||||
#if defined (__FreeBSD__) || defined (__APPLE__)
|
#if defined (__FreeBSD__) || defined (__APPLE__)
|
||||||
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
|
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
|
||||||
@@ -18,10 +22,10 @@
|
|||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#ifdef __FreeBSD__
|
||||||
|
#define fstat64 fstat
|
||||||
#ifndef __GPTSUPPORT
|
#define stat64 stat
|
||||||
#define __GPTSUPPORT
|
#endif
|
||||||
|
|
||||||
// Set this as a default
|
// Set this as a default
|
||||||
#define SECTOR_SIZE UINT32_C(512)
|
#define SECTOR_SIZE UINT32_C(512)
|
||||||
@@ -39,7 +43,7 @@
|
|||||||
// Number and size of GPT entries...
|
// Number and size of GPT entries...
|
||||||
#define NUM_GPT_ENTRIES 128
|
#define NUM_GPT_ENTRIES 128
|
||||||
#define GPT_SIZE 128
|
#define GPT_SIZE 128
|
||||||
#define HEADER_SIZE 92
|
#define HEADER_SIZE UINT32_C(92)
|
||||||
#define GPT_RESERVED 420
|
#define GPT_RESERVED 420
|
||||||
#define NAME_SIZE 72
|
#define NAME_SIZE 72
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user