Initial git repository creation, version 0.3.1 plus changes
This commit is contained in:
83
CHANGELOG
Normal file
83
CHANGELOG
Normal file
@@ -0,0 +1,83 @@
|
||||
0.3.1:
|
||||
------
|
||||
|
||||
- Added Mac OS X support, provided as a patch by an anonymous contributor.
|
||||
|
||||
- Fixed bug in disksize() function on Mac OS. (Possibly dependent on the
|
||||
kernel and/or GCC version.) The disk size, of type uint64_t, was not
|
||||
being passed correctly, so I reorganized the function to return it as
|
||||
the function's return value rather than as a parameter. This seems to
|
||||
work OK on my Mac OS test system and on both 32- and 64-bit Linux
|
||||
systems.
|
||||
|
||||
- Added test for writability when opening a disk for reading. If the
|
||||
test fails, a warning message is displayed. (The test simply opens
|
||||
the disk for writing and then closes it before writing any data,
|
||||
so the test shouldn't cause problems.)
|
||||
|
||||
- Fixed off-by-one bug in GPTData::FindLastAvailable().
|
||||
|
||||
- Fixed bug that caused display of options after a disk-write error.
|
||||
|
||||
- Fixed several incorrect MacOS X partition type GUIDs.
|
||||
|
||||
0.3.0:
|
||||
------
|
||||
|
||||
- Changed version number to 0.3.0, reflecting the fact that I've received
|
||||
no significant bug reports and so am elevating the program to "beta"
|
||||
status. This change also entailed altering the warning the program
|
||||
displays when saving partition table changes.
|
||||
|
||||
- Fixed minor bug in CHS geometry of the protective MBR's type EE partition
|
||||
(was producing 0x000200 as the start value, but should be 0x000100).
|
||||
Should be a non-critical bug since the protective MBR partition
|
||||
definition is only there to keep MBR-only disk utilities from messing
|
||||
with the disk.
|
||||
|
||||
- Added ability to enter GUIDs as single massive strings rather than in
|
||||
chunks.
|
||||
|
||||
0.2.2:
|
||||
------
|
||||
|
||||
- Added #include directives required to compile the program using GCC
|
||||
4.4.0.
|
||||
|
||||
0.2.1:
|
||||
------
|
||||
|
||||
- Fixed partition numbering problem in reports of partition overlaps in
|
||||
verification function.
|
||||
|
||||
- Fixed 1-sector partition size problem when creating new partitions
|
||||
(partitions were 1 sector too big when using the +size option).
|
||||
|
||||
- Changed BytesToSI() to display values in bytes without decimal points
|
||||
(e.g., "512 bytes" rather than "512.0 bytes").
|
||||
|
||||
- Added GPTData class member functions to retrieve GPT data structure
|
||||
locations on disk; used in my internal-use-only GPT-wiping program.
|
||||
|
||||
- Eliminated the "a reboot is recommended" notice after writing the
|
||||
partition table.
|
||||
|
||||
- Added notice after sorting the partition table to the effect that
|
||||
editing /etc/fstab and/or the boot loader files may be required.
|
||||
|
||||
- Fixed bug in MBR-reading function that caused 0x0f (Win95 LBA) and 0x85
|
||||
(Linux extended) extended partitions to not be read.
|
||||
|
||||
- Fixed bug in GetLastSector() (in support.cc) that would have prevented
|
||||
correct user entry of over-32-bit sector numbers on 32-bit systems.
|
||||
|
||||
- Made some changes/corrections to the partition type list in
|
||||
parttypes.cc. Most of these were based on newly-discovered MBR type
|
||||
codes for Apple (Mac OS X) filesystems.
|
||||
|
||||
- General code cleanup (setting explicit casts, etc.)
|
||||
|
||||
0.2.0:
|
||||
------
|
||||
|
||||
- Initial semi-public release
|
||||
340
COPYING
Normal file
340
COPYING
Normal file
@@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
||||
34
Makefile
Normal file
34
Makefile
Normal file
@@ -0,0 +1,34 @@
|
||||
CC=gcc
|
||||
CXX=g++
|
||||
#CFLAGS=-O2 -fpack-struct
|
||||
CFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
|
||||
CXXFLAGS=-O2 -fpack-struct -D_FILE_OFFSET_BITS=64 -g
|
||||
LIB_NAMES=support crc32 mbr gpt parttypes attributes
|
||||
LIB_SRCS=$(NAMES:=.cc)
|
||||
LIB_OBJS=$(LIB_NAMES:=.o)
|
||||
LIB_HEADERS=$(LIB_NAMES:=.h)
|
||||
DEPEND= makedepend $(CFLAGS)
|
||||
|
||||
#$(APPNAME): $(MBR2GPT_OBJS)
|
||||
# $(CC) $(MBR2GPT_OBJS) -o $@
|
||||
|
||||
gdisk: $(LIB_OBJS) gdisk.o
|
||||
$(CXX) $(LIB_OBJS) gdisk.o -o gdisk
|
||||
|
||||
wipegpt: $(LIB_OBJS) wipegpt.o
|
||||
$(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt
|
||||
|
||||
lint: #no pre-reqs
|
||||
lint $(SRCS)
|
||||
|
||||
clean: #no pre-reqs
|
||||
rm -f core *.o *~ gdisk
|
||||
|
||||
# what are the source dependencies
|
||||
depend: $(SRCS)
|
||||
$(DEPEND) $(SRCS)
|
||||
|
||||
$(OBJS):
|
||||
|
||||
# DO NOT DELETE
|
||||
|
||||
95
README
Normal file
95
README
Normal file
@@ -0,0 +1,95 @@
|
||||
GPT fdisk (aka gdisk)
|
||||
by Roderick W. Smith, rodsmith@rodsbooks.com
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This software is intended as a (somewhat) fdisk-workalike program for
|
||||
GPT-partitioned disks. Although libparted and programs that use it (GNU
|
||||
Parted, gparted, etc.) provide the ability to handle GPT disks, they have
|
||||
certain limitations that gdisk overcomes. Specific advantages of gdisk
|
||||
include:
|
||||
|
||||
* The ability to convert MBR-partitioned disks in-place to GPT format,
|
||||
without losing data
|
||||
|
||||
* The ability to specify sector-exact partition sizes
|
||||
|
||||
* More flexible specification of filesystem type code GUIDs, which
|
||||
GNU Parted tends to corrupt (particularly for FAT partitions)
|
||||
|
||||
* Clear identification of the number of unallocated sectors on a
|
||||
disk
|
||||
|
||||
* A user interface that's familiar to long-time users of Linux
|
||||
fdisk
|
||||
|
||||
* The MBR boot loader code is left alone (GNU Parted tends to
|
||||
wipe it out with every change)
|
||||
|
||||
Of course, gdisk isn't without its limitations. Most notably, it lacks the
|
||||
filesystem awareness and filesystem-related features of GNU Parted. You
|
||||
can't resize a partition's filesystem or create a partition with a
|
||||
filesystem already in place with gdisk, for instance. There's no GUI
|
||||
version of gdisk.
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
To compile gdisk, you must have appropriate development tools installed,
|
||||
most notably the GNU Compiler Collection (GCC) and its g++ compiler for
|
||||
C++. uncompress the package and type "make" at the command prompt in the
|
||||
resulting directory. The result should be a program file called gdisk. You
|
||||
can use this in place or copy the file to a suitable directory, such as
|
||||
/usr/local/sbin. You can copy the man page (gdisk.8) to /usr/local/man/man8
|
||||
to make it available.
|
||||
|
||||
Caveats
|
||||
-------
|
||||
|
||||
THIS SOFTWARE IS EARLY BETA SOFTWARE! IF IT WIPES OUT YOUR HARD DISK OR
|
||||
EATS YOUR CAT, DON'T BLAME ME! To date, I've tested the software mainly on
|
||||
two USB flash drives, 2 GiB and 8 GiB in size. I've also made a few minor
|
||||
tweaks to a production system with a 500 GiB hard disk and made more
|
||||
extensive changes to a handful of 80-160 GiB hard disks. I believe all
|
||||
data-corruption bugs to be squashed, but I know full well that the odds of
|
||||
my missing something are high. This is particularly true for large drives;
|
||||
I have no way of testing the software with > 2TiB drives, which will test
|
||||
the 64-bit sector pointer support.
|
||||
|
||||
The MBR-to-GPT feature seems to work well for data drives, but it's largely
|
||||
untested on boot drives. One attempt with Windows failed miserably, but I
|
||||
believe that was because of Windows' inherent limitations with respect to
|
||||
GPT. (The partitions themselves were intact.)
|
||||
|
||||
My main development platform is a system running the 64-bit version of
|
||||
Ubuntu. I've also tested on 64-bit OpenSuSE and 32-bit Fedora 10. Problems
|
||||
relating to 64-bit integers on the 32-bit Linux have been common during
|
||||
development and may crop up in the future. The Mac OS X support is new,
|
||||
and has at least one bug/limitation: It seems to be impossible to write
|
||||
a new partition table if any partitions from the disk are currently
|
||||
mounted.
|
||||
|
||||
Redistribution
|
||||
--------------
|
||||
|
||||
This program is licensed under terms of the GNU GPL (see the file COPYING).
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
|
||||
This code is mostly my own; however, I've used three functions from two
|
||||
other GPLed programs:
|
||||
|
||||
- The code used to generate CRCs is taken from the efone program by
|
||||
Krzysztof Dabrowski and ElysiuM deeZine. (See the crc32.h and
|
||||
crc32.cc source code files.)
|
||||
|
||||
- A function to find the disk size is taken from Linux fdisk by
|
||||
A. V. Le Blanc.
|
||||
|
||||
Additional code contributors include:
|
||||
|
||||
- Yves Blusseau (1otnwmz02@sneakemail.com)
|
||||
|
||||
- One anonymous contributor
|
||||
81
attributes.cc
Normal file
81
attributes.cc
Normal file
@@ -0,0 +1,81 @@
|
||||
// attributes.cc
|
||||
// Class to manage partition attribute codes. These are binary bit fields,
|
||||
// of which only three are currently (2/2009) documented on Wikipedia.
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "attributes.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Constructor. Its main task is to initialize the attribute name
|
||||
// data.
|
||||
Attributes::Attributes(void) {
|
||||
int i;
|
||||
char temp[ATR_NAME_SIZE];
|
||||
|
||||
// Most bits are undefined, so start by giving them an
|
||||
// appropriate name
|
||||
for (i = 1; i < NUM_ATR; i++) {
|
||||
sprintf(temp, "Undefined bit #%d", i);
|
||||
strcpy(atNames[i], temp);
|
||||
} // for
|
||||
|
||||
// Now reset those names that are defined....
|
||||
strcpy(atNames[0], "system partition");
|
||||
strcpy(atNames[60], "read-only");
|
||||
strcpy(atNames[62], "hidden");
|
||||
strcpy(atNames[63], "do not automount");
|
||||
} // Attributes constructor
|
||||
|
||||
// Destructor.
|
||||
Attributes::~Attributes(void) {
|
||||
} // Attributes destructor
|
||||
|
||||
// Display current attributes to user
|
||||
void Attributes::DisplayAttributes(void) {
|
||||
int i;
|
||||
|
||||
printf("Attribute value is %llX. Set fields are:\n",
|
||||
(unsigned long long) attributes);
|
||||
for (i = 0; i < NUM_ATR; i++) {
|
||||
if (((attributes >> i) % 2) == 1) { // bit is set
|
||||
/* if (strncmp("Undefined", atNames[i], 9) != 0)
|
||||
printf("%s\n", atNames[i]); */
|
||||
if (strncmp("Undefined", atNames[NUM_ATR - i - 1], 9) != 0)
|
||||
printf("%s\n", atNames[NUM_ATR - i - 1]);
|
||||
} // if
|
||||
} // for
|
||||
} // Attributes::DisplayAttributes()
|
||||
|
||||
// Prompt user for attribute changes
|
||||
void Attributes::ChangeAttributes(void) {
|
||||
int response, i;
|
||||
uint64_t bitValue;
|
||||
|
||||
printf("Known attributes are:\n");
|
||||
for (i = 0; i < NUM_ATR; i++) {
|
||||
if (strncmp("Undefined", atNames[i], 9) != 0)
|
||||
printf("%d - %s\n", i, atNames[i]);
|
||||
} // for
|
||||
|
||||
do {
|
||||
response = GetNumber(0, 64, -1, "Toggle which attribute field (0-63, 64 to exit): ");
|
||||
if (response != 64) {
|
||||
bitValue = PowerOf2(NUM_ATR - response - 1); // Find the integer value of the bit
|
||||
// bitValue = PowerOf2(response); // Find the integer value of the bit
|
||||
if ((bitValue & attributes) == bitValue) { // bit is set
|
||||
attributes -= bitValue; // so unset it
|
||||
printf("Have disabled the '%s' attribute.\n", atNames[response]);
|
||||
} else { // bit is not set
|
||||
attributes += bitValue; // so set it
|
||||
printf("Have enabled the '%s' attribute.\n", atNames[response]);
|
||||
} // if/else
|
||||
} // if
|
||||
} while (response != 64);
|
||||
} // Attributes::ChangeAttributes()
|
||||
|
||||
28
attributes.h
Normal file
28
attributes.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include "support.h"
|
||||
|
||||
#ifndef __GPT_ATTRIBUTES
|
||||
#define __GPT_ATTRIBUTES
|
||||
|
||||
#define NUM_ATR 64 /* # of attributes -- 64, since it's a 64-bit field */
|
||||
#define ATR_NAME_SIZE 25 /* maximum size of attribute names */
|
||||
|
||||
using namespace std;
|
||||
|
||||
class Attributes {
|
||||
protected:
|
||||
uint64_t attributes;
|
||||
char atNames[NUM_ATR][ATR_NAME_SIZE];
|
||||
public:
|
||||
Attributes(void);
|
||||
~Attributes(void);
|
||||
void SetAttributes(uint64_t a) {attributes = a;}
|
||||
uint64_t GetAttributes(void) {return attributes;}
|
||||
void DisplayAttributes(void);
|
||||
void ChangeAttributes(void);
|
||||
}; // class Attributes
|
||||
|
||||
#endif
|
||||
70
crc32.cc
Normal file
70
crc32.cc
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* efone - Distributed internet phone system.
|
||||
*
|
||||
* (c) 1999,2000 Krzysztof Dabrowski
|
||||
* (c) 1999,2000 ElysiuM deeZine
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
/* based on implementation by Finn Yannick Jacobs */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
|
||||
* so make sure, you call it before using the other
|
||||
* functions!
|
||||
*/
|
||||
u_int32_t crc_tab[256];
|
||||
|
||||
/* chksum_crc() -- to a given block, this one calculates the
|
||||
* crc32-checksum until the length is
|
||||
* reached. the crc32-checksum will be
|
||||
* the result.
|
||||
*/
|
||||
u_int32_t chksum_crc32 (unsigned char *block, unsigned int length)
|
||||
{
|
||||
register unsigned long crc;
|
||||
unsigned long i;
|
||||
|
||||
crc = 0xFFFFFFFF;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
|
||||
}
|
||||
return (crc ^ 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
/* chksum_crc32gentab() -- to a global crc_tab[256], this one will
|
||||
* calculate the crcTable for crc32-checksums.
|
||||
* it is generated to the polynom [..]
|
||||
*/
|
||||
|
||||
void chksum_crc32gentab ()
|
||||
{
|
||||
unsigned long crc, poly;
|
||||
int i, j;
|
||||
|
||||
poly = 0xEDB88320L;
|
||||
for (i = 0; i < 256; i++)
|
||||
{
|
||||
crc = i;
|
||||
for (j = 8; j > 0; j--)
|
||||
{
|
||||
if (crc & 1)
|
||||
{
|
||||
crc = (crc >> 1) ^ poly;
|
||||
}
|
||||
else
|
||||
{
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
crc_tab[i] = crc;
|
||||
}
|
||||
}
|
||||
20
crc32.h
Normal file
20
crc32.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* efone - Distributed internet phone system.
|
||||
*
|
||||
* (c) 1999,2000 Krzysztof Dabrowski
|
||||
* (c) 1999,2000 ElysiuM deeZine
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
/* based on implementation by Finn Yannick Jacobs. */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void chksum_crc32gentab ();
|
||||
uint32_t chksum_crc32 (unsigned char *block, unsigned int length);
|
||||
extern unsigned int crc_tab[256];
|
||||
602
gdisk.8
Normal file
602
gdisk.8
Normal file
@@ -0,0 +1,602 @@
|
||||
.\" Copyright 2009 Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||
.\" May be distributed under the GNU General Public License
|
||||
.TH GDISK 8 "August 2009" "Linux 2.6" "GPT fdisk Manual"
|
||||
.SH NAME
|
||||
gdisk \- GPT partition table manipulator for Linux
|
||||
.SH SYNOPSIS
|
||||
.BI "gdisk "
|
||||
[ \-l ]
|
||||
.I device
|
||||
.SH DESCRIPTION
|
||||
Hard disks can be divided into one or more segments, known as
|
||||
.IR partitions .
|
||||
This division is described in the
|
||||
.I "partition table"
|
||||
of the disk. Several different partition table formats exist, each with its
|
||||
advantages and disadvantages.
|
||||
|
||||
The original partitioning system used on PCs, now known as the
|
||||
.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 reach 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
|
||||
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
|
||||
.IR "gptsync",
|
||||
this should not be disturbed by most ordinary actions. Some advanced data
|
||||
recovery options require you to understand the distinctions between the
|
||||
main and backup data, as well as between the GPT headers and the partition
|
||||
tables.
|
||||
|
||||
The
|
||||
.B "gdisk"
|
||||
program employs a user interface similar to that of
|
||||
.BR "fdisk",
|
||||
but
|
||||
.B "gdisk"
|
||||
modifies GPT partitions. It also has the capability of transforming MBR
|
||||
partitions into GPT partitions. Like the original
|
||||
.B fdisk
|
||||
program,
|
||||
.B gdisk
|
||||
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
|
||||
save your partitions.
|
||||
|
||||
.B gdisk
|
||||
is a text-mode menu-driven program for creation and manipulation of
|
||||
partition tables. It will automatically convert an MBR partition table to
|
||||
GPT format, or will load a GPT partition table. When used with the
|
||||
.IR "\-l"
|
||||
command-line option, the program displays the current partition table and
|
||||
then exits.
|
||||
|
||||
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
|
||||
(CHS) addressing and logical block addressing (LBA). The former is klunky
|
||||
and limiting. GPT drops CHS addressing and uses 64-bit LBA mode
|
||||
exclusively. Thus, GPT data structures, and therefore
|
||||
.BR "gdisk",
|
||||
do not need to deal with CHS geometries and all the problems they create.
|
||||
Users of
|
||||
.BR "fdisk"
|
||||
will note that
|
||||
.B "gdisk"
|
||||
lacks the options and limitations associated with CHS geometries.
|
||||
|
||||
For best results, you should always use an OS-specific partition table
|
||||
program. For example, you should make Mac OS X partitions with the Mac OS
|
||||
X Disk Utility
|
||||
program and Linux partitions with the Linux
|
||||
.B "gdisk"
|
||||
or GNU Parted program.
|
||||
|
||||
Upon start,
|
||||
.B gdisk
|
||||
attempts to identify the partition type in use on the specified disk. If it
|
||||
finds valid GPT data,
|
||||
.B gdisk
|
||||
will use it. If
|
||||
.B gdisk
|
||||
finds a valid MBR but no GPT data, it will attempt to convert the MBR into
|
||||
GPT form. Upon exiting with the 'w' option,
|
||||
.B gdisk
|
||||
will then replace the MBR with a GPT.
|
||||
.IR "This action is potentially dangerous!"
|
||||
Your system may become unbootable, and partition type codes may become
|
||||
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
|
||||
mistakenly launch
|
||||
.B gdisk
|
||||
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
|
||||
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.
|
||||
(Doing this may require you to update your
|
||||
.IR "/etc/fstab"
|
||||
file.)
|
||||
|
||||
When creating a fresh partition table, certain considerations may be in
|
||||
order:
|
||||
|
||||
.TP
|
||||
.B *
|
||||
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
|
||||
and in whatever sizes are desired.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
Boot disks for EFI-based systems require an
|
||||
.IR "EFI System Partition" (
|
||||
.B "gdisk"
|
||||
internal code 0xEF00) formatted as FAT-32. The recommended size of this
|
||||
partition is 100 MiB. Boot-related files are stored here. (Note that GNU
|
||||
Parted identifies such partitions as having the "boot flag" set.)
|
||||
|
||||
.TP
|
||||
.B *
|
||||
If Windows is to boot from a GPT disk, a partition of type "Microsoft
|
||||
Reserved" (
|
||||
.B "gdisk"
|
||||
internal code 0x0C01) is recommended. This partition should be about 128 MiB
|
||||
in size. It ordinarily follows the EFI System Partition and immediately
|
||||
precedes the Windows data partitions. (Note that GNU Parted creates all
|
||||
FAT partitions as this type, which actually makes the partition unusable
|
||||
for normal file storage in both Windows and Mac OS X.)
|
||||
|
||||
.TP
|
||||
.B *
|
||||
Some OSes' GPT utilities create some blank space (typically 128 MiB) after
|
||||
each partition. The intent is to enable future disk utilities to use this
|
||||
space. Such free space is not required of GPT disks, but creating it may
|
||||
help in future disk maintenance.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-l
|
||||
List the partition tables for the specified devices and then exit.
|
||||
.PP
|
||||
|
||||
Most interactions with
|
||||
.B gdisk
|
||||
occur with its interactive text-mode menus. The main menu provides the
|
||||
following options:
|
||||
|
||||
.TP
|
||||
.B c
|
||||
Change the GPT name of a partition. This name is encoded as a UTF-16
|
||||
string, but
|
||||
.B gdisk
|
||||
supports only ASCII characters as names. For the most part, Linux ignores
|
||||
the partition name, but it may be important in some OSes.
|
||||
|
||||
.TP
|
||||
.B d
|
||||
Delete a partition. This action deletes the entry from the partition table
|
||||
but does not disturb the data within the sectors originally allocated to
|
||||
the partition on the disk.
|
||||
|
||||
.TP
|
||||
.B i
|
||||
Show detailed partition information. The summary information produced by
|
||||
the 'p' command necessarily omits many details, such as the partition's
|
||||
unique GUID and the translation of
|
||||
.BR "gdisk"'s
|
||||
internal partition type code to a plain type name. The 'i' option
|
||||
displays this information for a single partition.
|
||||
|
||||
.TP
|
||||
.B l
|
||||
Display a summary of partition types. GPT uses a GUID to identify
|
||||
partition types for particular OSes and purposes. For ease of data entry,
|
||||
.B gdisk
|
||||
compresses these into two-byte (four-digit hexadecimal) values that are
|
||||
related to their MBR codes. Specifically, the MBR code is multiplied by
|
||||
hexadecimal 0x0100. For instance, the code for Linux swap space in MBR is
|
||||
0x82, and it's 0x8200 in
|
||||
.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
|
||||
(entered as 0x0700 in
|
||||
.BR "gdisk" ).
|
||||
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,
|
||||
0xa501 for FreeBSD boot, 0xa502 for FreeBSD swap, and so on. Note that
|
||||
these two-byte codes are unique to
|
||||
.BR "gdisk".
|
||||
|
||||
.TP
|
||||
.B m
|
||||
Print the menu. Type this command (or any other unrecognized command) to
|
||||
see a summary of available options.
|
||||
|
||||
.TP
|
||||
.B n
|
||||
Create a new partition. This command is modelled after the equivalent
|
||||
.B fdisk
|
||||
option, although some differences exist. You enter a partition number,
|
||||
starting sector, and either an ending sector or increment (in integral
|
||||
multiples of sectors, kilobytes, megabytes, gigabytes, or terabytes). You
|
||||
must also set a partition type code.
|
||||
|
||||
.TP
|
||||
.B o
|
||||
Clear out all partition data. This includes GPT header data,
|
||||
all partition definitions, and the protective MBR.
|
||||
|
||||
.TP
|
||||
.B p
|
||||
Display basic partition summary data. This includes partition
|
||||
numbers, starting and ending sector numbers, partition sizes,
|
||||
.BR "gdisk"'s
|
||||
partition types codes, and partition names. For additional information,
|
||||
use the 'i' command.
|
||||
|
||||
.TP
|
||||
.B q
|
||||
Quit from the program
|
||||
.IR "without saving data".
|
||||
Use it if you just wanted to view information or if you make a mistake and
|
||||
want to back out of all your changes.
|
||||
|
||||
.TP
|
||||
.B s
|
||||
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.
|
||||
Note that some partitioning utilities, such as GNU Parted, will sort
|
||||
partitions whenever they make changes. Such changes will be reflected in
|
||||
your Linux device filenames, so you may need to edit
|
||||
.IR "/etc/fstab"
|
||||
if you use this option.
|
||||
|
||||
.TP
|
||||
.B t
|
||||
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
|
||||
GUID directly, if you have one and
|
||||
.B gdisk
|
||||
doesn't know it.
|
||||
|
||||
.TP
|
||||
.B v
|
||||
Verify disk. This option checks for a variety of problems, such as
|
||||
incorrect CRCs and mismatched main and backup data. This option does not
|
||||
automatically correct these problems, though; for that, you must use
|
||||
options on the experts' menu. If no problems are found, this command
|
||||
displays a summary of unallocated disk space.
|
||||
|
||||
.TP
|
||||
.B w
|
||||
Write data. Use this command to save your changes.
|
||||
|
||||
.TP
|
||||
.B x
|
||||
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.
|
||||
.PP
|
||||
|
||||
A few options on the experts' menu duplicate functionality on the main
|
||||
menu, for the sake of convenience; however, for the most part the experts'
|
||||
menu provides unusually dangerous or obscure options. These 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
|
||||
.B b
|
||||
Rebuild main 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
|
||||
your main GPT header was damaged or destroyed (say, by sloppy use of
|
||||
.IR "dd").
|
||||
.TP
|
||||
.B c
|
||||
Load backup partition table. Ordinarily,
|
||||
.B gdisk
|
||||
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
|
||||
damaged, you can use this option to load the backup from disk and use it
|
||||
instead. Note that this will almost certainly produce no or strange
|
||||
partition entries if you've just converted an MBR disk to GPT format, since
|
||||
there will be no backup partition table on disk.
|
||||
|
||||
.TP
|
||||
.B d
|
||||
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.
|
||||
.TP
|
||||
.B e
|
||||
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
|
||||
partition table (via 'c') but it's in worse shape then the main partition
|
||||
table.
|
||||
.TP
|
||||
.B f
|
||||
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.) Ordinarily,
|
||||
.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
|
||||
.B g
|
||||
Change disk GUID. Each disk has a unique GUID code, which
|
||||
.B gdisk
|
||||
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 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
|
||||
.B l
|
||||
Load partition data from a backup file. This option is the reverse of the 'k'
|
||||
option. Note that restoring partition data from anything but the
|
||||
original disk is not recommended.
|
||||
.TP
|
||||
.B m
|
||||
Print the menu. This option (or any unrecognized entry) displays a summary
|
||||
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
|
||||
.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
|
||||
.B r
|
||||
Return to the main menu. You can go back to the main menu with this option.
|
||||
.TP
|
||||
.B s
|
||||
Resize partition table. The partition table may be resized with this
|
||||
option. The default size is 128 entries. Officially, sizes of less than
|
||||
16KB (128 entries, given the normal entry size) are unsupported by the GPT
|
||||
specification; however, in practice they seem to work, and can sometimes be
|
||||
useful in converting MBR disks. Larger sizes also work fine. Linux imposes
|
||||
its own limits on the number of partitions, though.
|
||||
.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.
|
||||
.PP
|
||||
|
||||
In many cases, you can press the Enter key to select a default option when
|
||||
entering data. When only one option is possible,
|
||||
.B gdisk
|
||||
usually bypasses the prompt entirely.
|
||||
|
||||
.SH BUGS
|
||||
As of August of 2009 (version 0.3.1),
|
||||
.B gdisk
|
||||
should be considered early beta software. Known bugs and
|
||||
limitations include:
|
||||
|
||||
.TP
|
||||
.B *
|
||||
The program runs correctly only on little-endian (Intel and similar) CPUs.
|
||||
It should fail gracefully on PowerPC and other big-endian CPUs, but this
|
||||
hasn't been tested.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
The program compiles correctly only on Linux and Mac OS X. Both 64-bit
|
||||
(x86-64) and 32-bit (x86) versions for Linux have been tested, the former
|
||||
more thoroughly than the latter. The Mac OS X support was added with
|
||||
version 0.3.1 and has not been thoroughly tested.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
Under Mac OS X, the program will only save a partition table if no
|
||||
partitions from the disk are currently mounted. (This limitation does not
|
||||
exist in the Linux version of the program.)
|
||||
|
||||
.TP
|
||||
.B *
|
||||
The fields used to display the start and end sector numbers for partitions
|
||||
in the 'p' command are 14 characters wide. This translates to a limitation
|
||||
of about 45 PiB. On larger disks, the displayed columns will go out of
|
||||
alignment.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
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
|
||||
corrupted in the 'i' menu option's display; however, they should be
|
||||
preserved when loading and saving partitions.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
The program can load only up to 124 logical partitions when converting from
|
||||
MBR format. This limit can be raised by changing the #define NUM_LOGICALS
|
||||
line in the
|
||||
.IR "mbr.cc"
|
||||
source code file and recompiling; however, such a change will require using
|
||||
a larger-than-normal GPT partition table. (The limit of 124 logical
|
||||
partitions was chosen because that number plus the four primary partitions
|
||||
equals the 128 partitions supported by the most common GPT partition table
|
||||
size.)
|
||||
|
||||
.TP
|
||||
.B *
|
||||
Converting from MBR format sometimes fails because of insufficient space at
|
||||
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
|
||||
this problem; however, in extreme cases it may be necessary to resize a
|
||||
partition using GNU Parted or a similar tool.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
Converting from MBR supports only one extended partition. If multiple
|
||||
extended partitions are found, only the final extended partition's logical
|
||||
partitions are guaranteed to be converted intact; some or all of the
|
||||
earlier extended partition(s) logical partitions will be lost.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
MBR conversions work only if the disk has correct LBA partition
|
||||
descriptors. These descriptors should be present on any disk over 8 GiB in
|
||||
size or on smaller disks partitioned with any but very ancient software.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
If an MBR disk contains a FreeBSD disklabel partition, it's converted
|
||||
in-place as such rather than splitting out its constituent disklabel
|
||||
partitions into GPT partitions. Other OSes' disklabel partitions may not
|
||||
get appropriate GUID type codes at all.
|
||||
|
||||
.TP
|
||||
.B *
|
||||
Booting after converting an MBR disk may be 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 platforms, Windows through
|
||||
Vista doesn't support booting from GPT disks.
|
||||
.PP
|
||||
|
||||
.SH AUTHORS
|
||||
|
||||
Primary author: Roderick W. Smith (rodsmith@rodsbooks.com)
|
||||
|
||||
Contributors:
|
||||
|
||||
* Yves Blusseau (1otnwmz02@sneakemail.com)
|
||||
|
||||
* One anonymous contributor
|
||||
|
||||
.SH "SEE ALSO"
|
||||
.BR cfdisk (8),
|
||||
.BR fdisk (8),
|
||||
.BR mkfs (8),
|
||||
.BR parted (8),
|
||||
.BR sfdisk (8)
|
||||
|
||||
.IR "http://en.wikipedia.org/wiki/GUID_Partition_Table"
|
||||
|
||||
.IR "http://developer.apple.com/technotes/tn2006/tn2166.html"
|
||||
|
||||
.IR "http://www.rodsbooks.com/gdisk/"
|
||||
|
||||
.SH AVAILABILITY
|
||||
The gdisk command is part of the GPT fdisk package and is available from
|
||||
Rod Smith.
|
||||
270
gdisk.cc
Normal file
270
gdisk.cc
Normal file
@@ -0,0 +1,270 @@
|
||||
// gdisk.cc
|
||||
// Program modelled after Linux fdisk, but it manipulates GPT partitions
|
||||
// rather than MBR partitions.
|
||||
//
|
||||
// by Rod Smith, February 2009
|
||||
|
||||
//#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include "mbr.h"
|
||||
#include "gpt.h"
|
||||
#include "support.h"
|
||||
|
||||
// Function prototypes....
|
||||
// int ReadPartitions(char* filename, struct GPTData* theGPT);
|
||||
int DoCommand(char* filename, struct GPTData* theGPT);
|
||||
void ShowCommands(void);
|
||||
void ShowExpertCommands(void);
|
||||
int ExpertsMenu(char* filename, struct GPTData* theGPT);
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
GPTData theGPT;
|
||||
int doMore = 1;
|
||||
char* device = NULL;
|
||||
|
||||
printf("GPT fdisk (gdisk) version 0.3.1\n\n");
|
||||
|
||||
if (argc == 2) { // basic usage
|
||||
if (SizesOK()) {
|
||||
doMore = theGPT.LoadPartitions(argv[1]);
|
||||
while (doMore) {
|
||||
doMore = DoCommand(argv[1], &theGPT);
|
||||
} // while
|
||||
} // if
|
||||
} else if (argc == 3) { // usage with "-l" option
|
||||
if (SizesOK()) {
|
||||
if (strcmp(argv[1], "-l") == 0) {
|
||||
device = argv[2];
|
||||
} else if (strcmp(argv[2], "-l") == 0) {
|
||||
device = argv[1];
|
||||
} else { // 3 arguments, but none is "-l"
|
||||
fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
|
||||
} // if/elseif/else
|
||||
if (device != NULL) {
|
||||
doMore = theGPT.LoadPartitions(device);
|
||||
if (doMore) theGPT.DisplayGPTData();
|
||||
} // if
|
||||
} // if
|
||||
} else {
|
||||
fprintf(stderr, "Usage: %s [-l] device_file\n", argv[0]);
|
||||
} // if/else
|
||||
} // main
|
||||
|
||||
// Accept a command and execute it. Returns 0 if the command includes
|
||||
// an exit condition (such as a q or w command), 1 if more commands
|
||||
// should be processed.
|
||||
int DoCommand(char* filename, struct GPTData* theGPT) {
|
||||
char command, line[255];
|
||||
int retval = 1;
|
||||
PartTypes typeHelper;
|
||||
uint32_t temp1, temp2;
|
||||
|
||||
printf("\nCommand (m for help): ");
|
||||
fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
/* case 'b': case 'B':
|
||||
GetGUID();
|
||||
break; */
|
||||
case 'c': case 'C':
|
||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
||||
theGPT->SetName(theGPT->GetPartNum());
|
||||
else
|
||||
printf("No partitions\n");
|
||||
break;
|
||||
case 'd': case 'D':
|
||||
theGPT->DeletePartition();
|
||||
break;
|
||||
case 'i': case 'I':
|
||||
theGPT->ShowDetails();
|
||||
break;
|
||||
case 'l': case 'L':
|
||||
typeHelper.ShowTypes();
|
||||
break;
|
||||
case 'n': case 'N':
|
||||
theGPT->CreatePartition();
|
||||
break;
|
||||
case 'o': case 'O':
|
||||
theGPT->ClearGPTData();
|
||||
// theGPT->protectiveMBR.MakeProtectiveMBR();
|
||||
// theGPT->BlankPartitions();
|
||||
break;
|
||||
case 'p': case 'P':
|
||||
theGPT->DisplayGPTData();
|
||||
break;
|
||||
case 'q': case 'Q':
|
||||
retval = 0;
|
||||
break;
|
||||
case 's': case 'S':
|
||||
theGPT->SortGPT();
|
||||
printf("You may need to edit /etc/fstab and/or your boot loader configuration!\n");
|
||||
break;
|
||||
case 't': case 'T':
|
||||
theGPT->ChangePartType();
|
||||
break;
|
||||
case 'v': case 'V':
|
||||
if (theGPT->Verify() > 0) { // problems found
|
||||
printf("You may be able to correct the problems by using options on the experts\n"
|
||||
"menu (press 'x' at the command prompt). Good luck!\n");
|
||||
} // if
|
||||
break;
|
||||
case 'w': case 'W':
|
||||
if (theGPT->SaveGPTData() == 1)
|
||||
retval = 0;
|
||||
break;
|
||||
case 'x': case 'X':
|
||||
retval = ExpertsMenu(filename, theGPT);
|
||||
break;
|
||||
default:
|
||||
ShowCommands();
|
||||
break;
|
||||
} // switch
|
||||
return (retval);
|
||||
} // DoCommand()
|
||||
|
||||
void ShowCommands(void) {
|
||||
printf("c\tchange a partition's name\n");
|
||||
printf("d\tdelete a partition\n");
|
||||
printf("i\tshow detailed information on a partition\n");
|
||||
printf("l\tlist available partition types\n");
|
||||
printf("m\tprint this menu\n");
|
||||
printf("n\tadd a new partition\n");
|
||||
printf("o\tcreate a new empty GUID partition table (GPT)\n");
|
||||
printf("p\tprint the partition table\n");
|
||||
printf("q\tquit without saving changes\n");
|
||||
printf("s\tsort partitions\n");
|
||||
printf("t\tchange a partition's type code\n");
|
||||
printf("v\tverify disk\n");
|
||||
printf("w\twrite table to disk and exit\n");
|
||||
printf("x\textra functionality (experts only)\n");
|
||||
} // ShowCommands()
|
||||
|
||||
// Accept a command and execute it. Returns 0 if the command includes
|
||||
// an exit condition (such as a q or w command), 1 if more commands
|
||||
// should be processed.
|
||||
int ExpertsMenu(char* filename, struct GPTData* theGPT) {
|
||||
char command, line[255], buFile[255];
|
||||
int retval = 1;
|
||||
PartTypes typeHelper;
|
||||
uint32_t pn;
|
||||
uint32_t temp1, temp2;
|
||||
int goOn = 1;
|
||||
|
||||
do {
|
||||
printf("\nExpert command (m for help): ");
|
||||
fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &command);
|
||||
switch (command) {
|
||||
case 'a': case 'A':
|
||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0)
|
||||
theGPT->SetAttributes(theGPT->GetPartNum());
|
||||
else
|
||||
printf("No partitions\n");
|
||||
break;
|
||||
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':
|
||||
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
|
||||
pn = theGPT->GetPartNum();
|
||||
printf("Enter the partition's new unique GUID:\n");
|
||||
theGPT->SetPartitionGUID(pn, GetGUID());
|
||||
} else printf("No partitions\n");
|
||||
break;
|
||||
case 'g': case 'G':
|
||||
printf("Enter the disk's unique GUID:\n");
|
||||
theGPT->SetDiskGUID(GetGUID());
|
||||
break;
|
||||
/* case 'h': case 'H':
|
||||
theGPT->MakeHybrid();
|
||||
break; */
|
||||
case 'i': case 'I':
|
||||
theGPT->ShowDetails();
|
||||
break;
|
||||
case 'k': case 'K':
|
||||
printf("Enter backup filename to save: ");
|
||||
fgets(line, 255, stdin);
|
||||
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;
|
||||
case 'n': case 'N':
|
||||
theGPT->MakeProtectiveMBR();
|
||||
break;
|
||||
case 'o': case 'O':
|
||||
theGPT->DisplayMBRData();
|
||||
break;
|
||||
case 'p': case 'P':
|
||||
theGPT->DisplayGPTData();
|
||||
break;
|
||||
case 'q': case 'Q':
|
||||
retval = 0;
|
||||
goOn = 0;
|
||||
break;
|
||||
case 'r': case 'R':
|
||||
goOn = 0;
|
||||
break;
|
||||
case 's': case 'S':
|
||||
theGPT->ResizePartitionTable();
|
||||
break;
|
||||
case 'v': case 'V':
|
||||
theGPT->Verify();
|
||||
break;
|
||||
case 'w': case 'W':
|
||||
if (theGPT->SaveGPTData() == 1) {
|
||||
retval = 0;
|
||||
goOn = 0;
|
||||
} // if
|
||||
break;
|
||||
default:
|
||||
ShowExpertCommands();
|
||||
break;
|
||||
} // switch
|
||||
} while (goOn);
|
||||
return (retval);
|
||||
} // ExpertsMenu()
|
||||
|
||||
void ShowExpertCommands(void) {
|
||||
printf("a\tset attributes\n");
|
||||
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\tchange partition GUID\n");
|
||||
printf("g\tchange disk GUID\n");
|
||||
// printf("h\tmake hybrid MBR\n");
|
||||
printf("i\tshow detailed information on a partition\n");
|
||||
printf("k\tsave partition data to a backup file\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("o\tprint protective MBR data\n");
|
||||
printf("p\tprint the partition table\n");
|
||||
printf("q\tquit without saving changes\n");
|
||||
printf("r\treturn to main menu\n");
|
||||
printf("s\tresize partition table\n");
|
||||
printf("v\tverify disk\n");
|
||||
printf("w\twrite table to disk and exit\n");
|
||||
} // ShowExpertCommands()
|
||||
153
gpt.h
Normal file
153
gpt.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/* gpt.h -- GPT and data structure definitions, types, and
|
||||
functions */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "support.h"
|
||||
#include "parttypes.h"
|
||||
#include "mbr.h"
|
||||
|
||||
#ifndef __GPTSTRUCTS
|
||||
#define __GPTSTRUCTS
|
||||
|
||||
#define GPT_SIGNATURE UINT64_C(0x5452415020494645)
|
||||
|
||||
/* Number and size of GPT entries... */
|
||||
#define NUM_GPT_ENTRIES 128
|
||||
#define GPT_SIZE 128
|
||||
/* Offset, in 512-byte sectors, for GPT table and partition data.
|
||||
Note this is above two multiplied together, divided by 512, with 2
|
||||
added
|
||||
#define GPT_OFFSET (((NUM_GPT_ENTRIES * GPT_SIZE) / SECTOR_SIZE) + 2)
|
||||
*/
|
||||
|
||||
#define HEADER_SIZE 92
|
||||
|
||||
#define GPT_RESERVED 420
|
||||
#define NAME_SIZE 72
|
||||
|
||||
using namespace std;
|
||||
|
||||
/****************************************
|
||||
* *
|
||||
* GPTData class and related structures *
|
||||
* *
|
||||
****************************************/
|
||||
|
||||
// Validity state of GPT data
|
||||
enum GPTValidity {gpt_valid, gpt_corrupt, gpt_invalid};
|
||||
|
||||
// Which set of partition data to use
|
||||
enum WhichToUse {use_gpt, use_mbr, use_new};
|
||||
|
||||
// Header (first 512 bytes) of GPT table
|
||||
struct GPTHeader {
|
||||
uint64_t signature;
|
||||
uint32_t revision;
|
||||
uint32_t headerSize;
|
||||
uint32_t headerCRC;
|
||||
uint32_t reserved;
|
||||
uint64_t currentLBA;
|
||||
uint64_t backupLBA;
|
||||
uint64_t firstUsableLBA;
|
||||
uint64_t lastUsableLBA;
|
||||
struct GUIDData diskGUID;
|
||||
uint64_t partitionEntriesLBA;
|
||||
uint32_t numParts;
|
||||
uint32_t sizeOfPartitionEntries;
|
||||
uint32_t partitionEntriesCRC;
|
||||
unsigned char reserved2[GPT_RESERVED];
|
||||
}; // struct GPTHeader
|
||||
|
||||
struct GPTPartition {
|
||||
struct GUIDData partitionType;
|
||||
struct GUIDData uniqueGUID;
|
||||
uint64_t firstLBA;
|
||||
uint64_t lastLBA;
|
||||
uint64_t attributes;
|
||||
unsigned char name[NAME_SIZE];
|
||||
}; // struct GPTPartition
|
||||
|
||||
// Data in GPT format
|
||||
class GPTData {
|
||||
protected:
|
||||
struct GPTHeader mainHeader;
|
||||
struct GPTPartition *partitions;
|
||||
struct GPTHeader secondHeader;
|
||||
MBRData protectiveMBR;
|
||||
char device[256]; // device filename
|
||||
uint32_t blockSize; // device block size
|
||||
uint64_t diskSize; // size of device, in blocks
|
||||
GPTValidity state; // is GPT valid?
|
||||
int mainCrcOk;
|
||||
int secondCrcOk;
|
||||
int mainPartsCrcOk;
|
||||
int secondPartsCrcOk;
|
||||
// uint32_t units; // display units, in multiples of sectors
|
||||
PartTypes typeHelper;
|
||||
public:
|
||||
GPTData(void);
|
||||
GPTData(char* deviceFilename);
|
||||
~GPTData(void);
|
||||
int SetGPTSize(uint32_t numEntries);
|
||||
int CheckGPTSize(void);
|
||||
int LoadPartitions(char* deviceFilename);
|
||||
int ForceLoadGPTData(int fd);
|
||||
int LoadMainTable(void);
|
||||
WhichToUse UseWhichPartitions(void);
|
||||
void ResizePartitionTable(void);
|
||||
int GetPartRange(uint32_t* low, uint32_t* high);
|
||||
void DisplayGPTData(void);
|
||||
void DisplayMBRData(void) {protectiveMBR.DisplayMBRData();}
|
||||
void ShowDetails(void);
|
||||
void ShowPartDetails(uint32_t partNum);
|
||||
void CreatePartition(void);
|
||||
void DeletePartition(void);
|
||||
void BlankPartitions(void);
|
||||
uint64_t FindFirstAvailable(uint64_t start = 0);
|
||||
uint64_t FindLastAvailable(uint64_t start);
|
||||
uint64_t FindLastInFree(uint64_t start);
|
||||
int IsFree(uint64_t sector);
|
||||
int XFormPartitions(MBRData* origParts);
|
||||
void SortGPT(void);
|
||||
int ClearGPTData(void);
|
||||
void ChangePartType(void);
|
||||
uint32_t GetPartNum(void);
|
||||
void SetAttributes(uint32_t partNum);
|
||||
void SetName(uint32_t partNum, char* theName = NULL);
|
||||
void SetDiskGUID(GUIDData newGUID);
|
||||
int SetPartitionGUID(uint32_t pn, GUIDData theGUID);
|
||||
int CheckHeaderValidity(void);
|
||||
int CheckHeaderCRC(struct GPTHeader* header);
|
||||
void RecomputeCRCs(void);
|
||||
int Verify(void);
|
||||
void RebuildMainHeader(void);
|
||||
void RebuildSecondHeader(void);
|
||||
void LoadSecondTableAsMain(void);
|
||||
uint64_t FindFreeBlocks(int *numSegments, uint64_t *largestSegment);
|
||||
// void MakeHybrid(void);
|
||||
void MakeProtectiveMBR(void) {return protectiveMBR.MakeProtectiveMBR();}
|
||||
int SaveGPTData(void);
|
||||
int SaveGPTBackup(char* filename);
|
||||
int LoadGPTBackup(char* filename);
|
||||
|
||||
// Return data about the GPT structures....
|
||||
uint32_t GetNumParts(void) {return mainHeader.numParts;}
|
||||
uint64_t GetMainHeaderLBA(void) {return mainHeader.currentLBA;}
|
||||
uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;}
|
||||
uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;}
|
||||
uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;}
|
||||
uint64_t GetBlocksInPartTable(void) {return (mainHeader.numParts *
|
||||
mainHeader.sizeOfPartitionEntries) / blockSize;}
|
||||
}; // class GPTData
|
||||
|
||||
// Function prototypes....
|
||||
void BlankPartition(struct GPTPartition* partition);
|
||||
//int XFormType(uint8_t oldType, struct GUIDData* newType, int partNum);
|
||||
void QuickSortGPT(struct GPTPartition* partitions, int start, int finish);
|
||||
int TheyOverlap(struct GPTPartition* first, struct GPTPartition* second);
|
||||
void ChangeGPTType(struct GPTPartition* part);
|
||||
int SizesOK(void);
|
||||
|
||||
#endif
|
||||
447
mbr.cc
Normal file
447
mbr.cc
Normal file
@@ -0,0 +1,447 @@
|
||||
/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
|
||||
data. */
|
||||
|
||||
/* By Rod Smith, January to February, 2009 */
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include "mbr.h"
|
||||
#include "support.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/****************************************
|
||||
* *
|
||||
* MBRData class and related structures *
|
||||
* *
|
||||
****************************************/
|
||||
|
||||
MBRData::MBRData(void) {
|
||||
blockSize = SECTOR_SIZE;
|
||||
diskSize = 0;
|
||||
strcpy(device, "");
|
||||
state = invalid;
|
||||
srand((unsigned int) time(NULL));
|
||||
EmptyMBR();
|
||||
} // MBRData default constructor
|
||||
|
||||
MBRData::MBRData(char *filename) {
|
||||
blockSize = SECTOR_SIZE;
|
||||
diskSize = 0;
|
||||
strcpy(device, filename);
|
||||
state = invalid;
|
||||
|
||||
srand((unsigned int) time(NULL));
|
||||
// Try to read the specified partition table, but if it fails....
|
||||
if (!ReadMBRData(filename)) {
|
||||
EmptyMBR();
|
||||
strcpy(device, "");
|
||||
} // if
|
||||
} // MBRData(char *filename) constructor
|
||||
|
||||
MBRData::~MBRData(void) {
|
||||
} // MBRData destructor
|
||||
|
||||
// Empty all data. Meant mainly for calling by constructors
|
||||
void MBRData::EmptyMBR(void) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 440; i++)
|
||||
code[i] = 0;
|
||||
diskSignature = (uint32_t) rand();
|
||||
nulls = 0;
|
||||
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
|
||||
// data isn't a valid MBR), 0 if the read failed.
|
||||
int MBRData::ReadMBRData(char* deviceFilename) {
|
||||
int fd, allOK = 1;
|
||||
|
||||
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
|
||||
ReadMBRData(fd);
|
||||
} else {
|
||||
allOK = 0;
|
||||
} // if
|
||||
|
||||
close(fd);
|
||||
|
||||
if (allOK)
|
||||
strcpy(device, deviceFilename);
|
||||
|
||||
return allOK;
|
||||
} // MBRData::ReadMBRData(char* deviceFilename)
|
||||
|
||||
// Read data from MBR.
|
||||
void MBRData::ReadMBRData(int fd) {
|
||||
int allOK = 1, i;
|
||||
int err;
|
||||
|
||||
// Clear logical partition array
|
||||
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
|
||||
|
||||
read(fd, code, 440);
|
||||
read(fd, &diskSignature, 4);
|
||||
read(fd, &nulls, 2);
|
||||
read(fd, partitions, 64);
|
||||
read(fd, &MBRSignature, 2);
|
||||
if (MBRSignature != MBR_SIGNATURE) {
|
||||
allOK = 0;
|
||||
state = invalid;
|
||||
fprintf(stderr, "MBR signature invalid; read 0x%04X, but should be 0x%04X\n",
|
||||
(unsigned int) MBRSignature, (unsigned int) MBR_SIGNATURE);
|
||||
} /* if */
|
||||
|
||||
// Find disk size
|
||||
diskSize = disksize(fd, &err);
|
||||
|
||||
// Find block size
|
||||
if ((blockSize = GetBlockSize(fd)) == -1) {
|
||||
blockSize = SECTOR_SIZE;
|
||||
printf("Unable to determine sector size; assuming %lu bytes!\n",
|
||||
(unsigned long) SECTOR_SIZE);
|
||||
} // if
|
||||
|
||||
// Load logical partition data, if any is found....
|
||||
if (allOK) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
|
||||
|| (partitions[i].partitionType == 0x85)) {
|
||||
// Found it, so call a recursive algorithm to load everything from them....
|
||||
allOK = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), 0);
|
||||
} // if
|
||||
} // for
|
||||
if (allOK) { // Loaded logicals OK
|
||||
state = mbr;
|
||||
} else {
|
||||
state = invalid;
|
||||
} // if
|
||||
} // if
|
||||
|
||||
/* Check to see if it's in GPT format.... */
|
||||
if (allOK) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (partitions[i].partitionType == UINT8_C(0xEE)) {
|
||||
state = gpt;
|
||||
} /* if */
|
||||
} /* for */
|
||||
} /* if */
|
||||
|
||||
/* // 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)
|
||||
|
||||
// Write the MBR data to the default defined device.
|
||||
int MBRData::WriteMBRData(void) {
|
||||
int allOK = 1, fd;
|
||||
|
||||
if ((fd = open(device, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) {
|
||||
WriteMBRData(fd);
|
||||
} else {
|
||||
allOK = 0;
|
||||
} // if/else
|
||||
close(fd);
|
||||
return allOK;
|
||||
} // MBRData::WriteMBRData(void)
|
||||
|
||||
// Save the MBR data to a file. Note that this function writes ONLY the
|
||||
// MBR data, not the logical partitions (if any are defined).
|
||||
void MBRData::WriteMBRData(int fd) {
|
||||
write(fd, code, 440);
|
||||
write(fd, &diskSignature, 4);
|
||||
write(fd, &nulls, 2);
|
||||
write(fd, partitions, 64);
|
||||
write(fd, &MBRSignature, 2);
|
||||
} // 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
|
||||
int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
|
||||
uint32_t diskOffset, int partNum) {
|
||||
int allOK = 1;
|
||||
struct EBRRecord ebr;
|
||||
off_t offset;
|
||||
|
||||
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);
|
||||
allOK = 0;
|
||||
}
|
||||
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);
|
||||
allOK = 0;
|
||||
}
|
||||
if (ebr.MBRSignature != MBR_SIGNATURE) {
|
||||
allOK = 0;
|
||||
printf("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)) && allOK) {
|
||||
allOK = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
|
||||
partNum + 1);
|
||||
} // if
|
||||
return (allOK);
|
||||
} // MBRData::ReadLogicalPart()
|
||||
|
||||
// Show the MBR data to the user....
|
||||
void MBRData::DisplayMBRData(void) {
|
||||
int i;
|
||||
char tempStr[255];
|
||||
|
||||
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
|
||||
printf("MBR partitions:\n");
|
||||
printf("Number\t Start (block)\t Length (blocks)\tType\n");
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (partitions[i].lengthLBA != 0) {
|
||||
printf("%4d\t%13lu\t%15lu \t0x%02X\n", i + 1, (unsigned long) partitions[i].firstLBA,
|
||||
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
|
||||
} // if
|
||||
} // for
|
||||
|
||||
// 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));
|
||||
} // MBRData::DisplayMBRData()
|
||||
|
||||
// Create a protective MBR
|
||||
void MBRData::MakeProtectiveMBR(void) {
|
||||
int i;
|
||||
|
||||
// Initialize variables
|
||||
nulls = 0;
|
||||
MBRSignature = MBR_SIGNATURE;
|
||||
|
||||
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
|
||||
// possible -- even to the point of exceeding the capacity of sub-8GB
|
||||
// disks. The EFI spec says to use 0xffffff as the ending value,
|
||||
// although normal MBR disks max out at 0xfeffff. FWIW, both GNU Parted
|
||||
// and Apple's Disk Utility use 0xfeffff, and the latter puts that
|
||||
// value in for the FIRST sector, too!
|
||||
partitions[0].firstSector[0] = UINT8_C(0);
|
||||
partitions[0].firstSector[1] = UINT8_C(1);
|
||||
partitions[0].firstSector[2] = UINT8_C(0);
|
||||
partitions[0].lastSector[0] = UINT8_C(255);
|
||||
partitions[0].lastSector[1] = UINT8_C(255);
|
||||
partitions[0].lastSector[2] = UINT8_C(255);
|
||||
|
||||
partitions[0].partitionType = UINT8_C(0xEE);
|
||||
partitions[0].firstLBA = UINT32_C(1);
|
||||
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
|
||||
partitions[0].lengthLBA = diskSize - 1;
|
||||
} else { // disk is too big to represent, so fake it...
|
||||
partitions[0].lengthLBA = UINT32_MAX;
|
||||
} // 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;
|
||||
} // MBRData::MakeProtectiveMBR()
|
||||
|
||||
// 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 < 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
|
||||
void MBRData::ShowState(void) {
|
||||
switch (state) {
|
||||
case invalid:
|
||||
printf("invalid");
|
||||
break;
|
||||
case gpt:
|
||||
printf("gpt");
|
||||
break;
|
||||
case hybrid:
|
||||
printf("hybrid");
|
||||
break;
|
||||
case mbr:
|
||||
printf("mbr");
|
||||
break;
|
||||
default:
|
||||
printf("unknown -- bug!");
|
||||
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()
|
||||
|
||||
uint8_t MBRData::GetStatus(int i) {
|
||||
MBRRecord* thePart;
|
||||
uint8_t retval;
|
||||
|
||||
thePart = GetPartition(i);
|
||||
if (thePart != NULL)
|
||||
retval = thePart->status;
|
||||
else
|
||||
retval = UINT8_C(0);
|
||||
return retval;
|
||||
} // MBRData::GetStatus()
|
||||
|
||||
uint8_t MBRData::GetType(int i) {
|
||||
MBRRecord* thePart;
|
||||
uint8_t retval;
|
||||
|
||||
thePart = GetPartition(i);
|
||||
if (thePart != NULL)
|
||||
retval = thePart->partitionType;
|
||||
else
|
||||
retval = UINT8_C(0);
|
||||
return retval;
|
||||
} // MBRData::GetType()
|
||||
|
||||
uint32_t MBRData::GetFirstSector(int i) {
|
||||
MBRRecord* thePart;
|
||||
uint32_t retval;
|
||||
|
||||
thePart = GetPartition(i);
|
||||
if (thePart != NULL) {
|
||||
retval = thePart->firstLBA;
|
||||
} else
|
||||
retval = UINT32_C(0);
|
||||
return retval;
|
||||
} // MBRData::GetFirstSector()
|
||||
|
||||
uint32_t MBRData::GetLength(int i) {
|
||||
MBRRecord* thePart;
|
||||
uint32_t retval;
|
||||
|
||||
thePart = GetPartition(i);
|
||||
if (thePart != NULL) {
|
||||
retval = thePart->lengthLBA;
|
||||
} else
|
||||
retval = UINT32_C(0);
|
||||
return retval;
|
||||
} // MBRData::GetLength()
|
||||
95
mbr.h
Normal file
95
mbr.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* mbr.h -- MBR data structure definitions, types, and functions */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#ifndef __MBRSTRUCTS
|
||||
#define __MBRSTRUCTS
|
||||
|
||||
#define MBR_SIGNATURE UINT16_C(0xAA55)
|
||||
|
||||
// Maximum number of logical partitions supported
|
||||
#define NUM_LOGICALS 124
|
||||
|
||||
using namespace std;
|
||||
|
||||
/****************************************
|
||||
* *
|
||||
* MBRData class and related structures *
|
||||
* *
|
||||
****************************************/
|
||||
|
||||
// Data for a single MBR partition record
|
||||
// Note that firstSector and lastSector are in CHS addressing, which
|
||||
// splits the bits up in a weird way.
|
||||
struct MBRRecord {
|
||||
uint8_t status;
|
||||
uint8_t firstSector[3];
|
||||
uint8_t partitionType;
|
||||
uint8_t lastSector[3];
|
||||
uint32_t firstLBA;
|
||||
uint32_t lengthLBA;
|
||||
}; // struct MBRRecord
|
||||
|
||||
// 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
|
||||
enum MBRValidity {invalid, gpt, hybrid, mbr};
|
||||
|
||||
// Full data in tweaked MBR format
|
||||
class MBRData {
|
||||
protected:
|
||||
uint8_t code[440];
|
||||
uint32_t diskSignature;
|
||||
uint16_t nulls;
|
||||
struct MBRRecord partitions[4];
|
||||
uint16_t MBRSignature;
|
||||
|
||||
// Above are basic MBR data; now add more stuff....
|
||||
uint32_t blockSize; // block size (usually 512)
|
||||
uint64_t diskSize; // size in blocks
|
||||
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;
|
||||
struct MBRRecord* GetPartition(int i); // Return primary or logical partition
|
||||
public:
|
||||
MBRData(void);
|
||||
MBRData(char* deviceFilename);
|
||||
~MBRData(void);
|
||||
void EmptyMBR(void);
|
||||
int ReadMBRData(char* deviceFilename);
|
||||
void ReadMBRData(int fd);
|
||||
int WriteMBRData(void);
|
||||
void WriteMBRData(int fd);
|
||||
int ReadLogicalPart(int fd, uint32_t extendedStart, uint32_t diskOffset,
|
||||
int partNum);
|
||||
void DisplayMBRData(void);
|
||||
void MakeProtectiveMBR(void);
|
||||
MBRValidity GetValidity(void) {return state;}
|
||||
void ShowState(void);
|
||||
void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
|
||||
int bootable = 0);
|
||||
|
||||
// Functions to extract data on specific partitions....
|
||||
uint8_t GetStatus(int i);
|
||||
uint8_t GetType(int i);
|
||||
uint32_t GetFirstSector(int i);
|
||||
uint32_t GetLength(int i);
|
||||
}; // struct MBRData
|
||||
|
||||
#endif
|
||||
332
parttypes.cc
Normal file
332
parttypes.cc
Normal file
@@ -0,0 +1,332 @@
|
||||
// parttypes.cc
|
||||
// Class to manage partition type codes -- a slight variant on MBR type
|
||||
// codes, GUID type codes, and associated names.
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "parttypes.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int PartTypes::numInstances = 0;
|
||||
AType* PartTypes::allTypes = NULL;
|
||||
AType* PartTypes::lastType = NULL;
|
||||
|
||||
// Constructor. Its main task is to initialize the data list, but only
|
||||
// if this is the first instance, since it's a static linked list.
|
||||
// Partition type codes are MBR type codes multiplied by 0x0100, with
|
||||
// additional related codes taking on following numbers. For instance,
|
||||
// the FreeBSD disklabel code in MBR is 0xa5; here, it's 0xa500, with
|
||||
// additional FreeBSD codes being 0xa501, 0xa502, and so on. This gives
|
||||
// related codes similar numbers and (given appropriate entry positions
|
||||
// in the linked list) keeps them together in the listings generated
|
||||
// by typing "L" at the main gdisk menu.
|
||||
// See http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
|
||||
// for a list of MBR partition type codes.
|
||||
PartTypes::PartTypes(void) {
|
||||
|
||||
numInstances++;
|
||||
if (numInstances == 1) {
|
||||
|
||||
// Start with the "unused entry," which should normally appear only
|
||||
// on empty partition table entries....
|
||||
AddType(0x0000, UINT64_C(0x0000000000000000), UINT64_C(0x0000000000000000),
|
||||
"Unused entry", 0);
|
||||
|
||||
// DOS/Windows partition types, which confusingly Linux also uses in GPT
|
||||
AddType(0x0100, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // FAT-12
|
||||
AddType(0x0400, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // FAT-16 < 32M
|
||||
AddType(0x0600, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // FAT-16
|
||||
AddType(0x0700, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 1); // NTFS (or could be HPFS)
|
||||
AddType(0x0b00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // FAT-32
|
||||
AddType(0x0c00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // FAT-32 LBA
|
||||
AddType(0x0c01, UINT64_C(0x4DB80B5CE3C9E316), UINT64_C(0xAE1502F02DF97D81),
|
||||
"Microsoft Reserved"); // Microsoft reserved
|
||||
AddType(0x0e00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // FAT-16 LBA
|
||||
AddType(0x1100, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Hidden FAT-12
|
||||
AddType(0x1400, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Hidden FAT-16 < 32M
|
||||
AddType(0x1600, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Hidden FAT-16
|
||||
AddType(0x1700, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Hidden NTFS (or could be HPFS)
|
||||
AddType(0x1b00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Hidden FAT-32
|
||||
AddType(0x1c00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Hidden FAT-32 LBA
|
||||
AddType(0x1e00, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Hidden FAT-16 LBA
|
||||
AddType(0x2700, UINT64_C(0x4D4006D1DE94BBA4), UINT64_C(0xACD67901D5BF6AA1),
|
||||
"Windows RE"); // Windows RE
|
||||
AddType(0x4200, UINT64_C(0x4F621431Af9B60A0), UINT64_C(0xAD694A71113368BC),
|
||||
"Windows LDM data"); // Logical disk manager
|
||||
AddType(0x4201, UINT64_C(0x42E07E8F5808C8AA), UINT64_C(0xB3CF3404E9E1D285),
|
||||
"Windows LDM metadata"); // Logical disk manager
|
||||
|
||||
// Linux-specific partition types....
|
||||
AddType(0x8200, UINT64_C(0x43C4A4AB0657FD6D), UINT64_C(0x4F4F4BC83309E584),
|
||||
"Linux swap"); // Linux swap (or could be Solaris)
|
||||
AddType(0x8300, UINT64_C(0x4433B9E5EBD0A0A2), UINT64_C(0xC79926B7B668C087),
|
||||
"Linux/Windows data", 0); // Linux native
|
||||
AddType(0x8301, UINT64_C(0x60C000078DA63339), UINT64_C(0x080923C83A0836C4),
|
||||
"Linux Reserved"); // Linux reserved
|
||||
AddType(0x8e00, UINT64_C(0x44C2F507E6D6D379), UINT64_C(0x28F93D2A8F233CA2),
|
||||
"Linux LVM"); // Linux LVM
|
||||
|
||||
// FreeBSD partition types....
|
||||
// Note: Rather than extract FreeBSD disklabel data, convert FreeBSD
|
||||
// partitions in-place, and let FreeBSD sort out the details....
|
||||
AddType(0xa500, UINT64_C(0x11D66ECF516E7CB4), UINT64_C(0x2B71092D0200F88F),
|
||||
"FreeBSD disklabel"); // FreeBSD disklabel
|
||||
AddType(0xa501, UINT64_C(0x11DC7F4183BD6B9D), UINT64_C(0x0F4FB86015000BBE),
|
||||
"FreeBSD boot"); // FreeBSD boot
|
||||
AddType(0xa502, UINT64_C(0x11D66ECF516E7CB5), UINT64_C(0x2B71092D0200F88F),
|
||||
"FreeBSD swap"); // FreeBSD swap
|
||||
AddType(0xa503, UINT64_C(0x11D66ECF516E7CB6), UINT64_C(0x2B71092D0200F88F),
|
||||
"FreeBSD UFS"); // FreeBSD UFS
|
||||
AddType(0xa504, UINT64_C(0x11D66ECF516E7CBA), UINT64_C(0x2B71092D0200F88F),
|
||||
"FreeBSD ZFS"); // FreeBSD ZFS
|
||||
AddType(0xa505, UINT64_C(0x11D66ECF516E7CB8), UINT64_C(0x2B71092D0200F88F),
|
||||
"FreeBSD Vinum/RAID"); // FreeBSD Vinum
|
||||
|
||||
// A MacOS partition type, separated from others by NetBSD partition types...
|
||||
AddType(0xa800, UINT64_C(0x11AA000055465300), UINT64_C(0xACEC4365300011AA),
|
||||
"Apple UFS"); // MacOS X
|
||||
|
||||
// NetBSD partition types. Note that the main entry sets it up as a
|
||||
// FreeBSD disklabel. I'm not 100% certain this is the correct behavior.
|
||||
AddType(0xa900, UINT64_C(0x11D66ECF516E7CB4), UINT64_C(0x2B71092D0200F88F),
|
||||
"FreeBSD disklabel", 0); // NetBSD disklabel
|
||||
AddType(0xa901, UINT64_C(0x11DCB10E49F48D32), UINT64_C(0x489687D119009BB9),
|
||||
"NetBSD swap");
|
||||
AddType(0xa902, UINT64_C(0x11DCB10E49F48D5A), UINT64_C(0x489687D119009BB9),
|
||||
"NetBSD FFS");
|
||||
AddType(0xa903, UINT64_C(0x11DCB10E49F48D82), UINT64_C(0x489687D119009BB9),
|
||||
"NetBSD LFS");
|
||||
AddType(0xa903, UINT64_C(0x11DCB10E49F48DAA), UINT64_C(0x489687D119009BB9),
|
||||
"NetBSD RAID");
|
||||
AddType(0xa904, UINT64_C(0x11DCB10F2DB519C4), UINT64_C(0x489687D119009BB9),
|
||||
"NetBSD concatenated");
|
||||
AddType(0xa905, UINT64_C(0x11DCB10F2DB519EC), UINT64_C(0x489687D119009BB9),
|
||||
"NetBSD encrypted");
|
||||
|
||||
// MacOS partition types (See also 0xa800, above)....
|
||||
AddType(0xab00, UINT64_C(0x11AA0000426F6F74), UINT64_C(0xACEC4365300011AA),
|
||||
"Apple boot"); // MacOS X
|
||||
AddType(0xaf00, UINT64_C(0x11AA000048465300), UINT64_C(0xACEC4365300011AA),
|
||||
"Apple HFS/HFS+"); // MacOS X
|
||||
AddType(0xaf01, UINT64_C(0x11AA000052414944), UINT64_C(0xACEC4365300011AA),
|
||||
"Apple RAID"); // MacOS X
|
||||
AddType(0xaf02, UINT64_C(0x11AA5F4F52414944), UINT64_C(0xACEC4365300011AA),
|
||||
"Apple RAID offline"); // MacOS X
|
||||
AddType(0xaf03, UINT64_C(0x11AA6C004C616265), UINT64_C(0xACEC4365300011AA),
|
||||
"Apple label"); // MacOS X
|
||||
AddType(0xaf04, UINT64_C(0x11AA76655265636F), UINT64_C(0xACEC4365300011AA),
|
||||
"AppleTV recovery"); // MacOS X
|
||||
|
||||
// Solaris partition types (one of which is shared with MacOS)
|
||||
AddType(0xbe00, UINT64_C(0x11B21DD26A82CB45), UINT64_C(0x316673200008A699),
|
||||
"Solaris boot"); // Solaris boot
|
||||
AddType(0xbf00, UINT64_C(0x11B21DD26a85CF4D), UINT64_C(0x316673200008A699),
|
||||
"Solaris root"); // Solaris root
|
||||
AddType(0xbf01, UINT64_C(0x11B21DD26A898CC3), UINT64_C(0x316673200008A699),
|
||||
"Solaris /usr & Mac ZFS"); // MacOS X & Solaris
|
||||
AddType(0xbf02, UINT64_C(0x11B21DD26A87C46F), UINT64_C(0x316673200008A699),
|
||||
"Solaris swap");
|
||||
AddType(0xbf03, UINT64_C(0x11B21DD26A8B642B), UINT64_C(0x316673200008A699),
|
||||
"Solaris backup");
|
||||
AddType(0xbf04, UINT64_C(0x11B21DD26A8EF2E9), UINT64_C(0x316673200008A699),
|
||||
"Solaris /var");
|
||||
AddType(0xbf05, UINT64_C(0x11B21DD26A90BA39), UINT64_C(0x316673200008A699),
|
||||
"Solaris /home");
|
||||
AddType(0xbf05, UINT64_C(0x11B21DD26A9283A5), UINT64_C(0x316673200008A699),
|
||||
"Solaris EFI_ALTSCTR");
|
||||
AddType(0xbf06, UINT64_C(0x11B21DD26A945A3B), UINT64_C(0x316673200008A699),
|
||||
"Solaris Reserved 1");
|
||||
AddType(0xbf07, UINT64_C(0x11B21DD26A9630D1), UINT64_C(0x316673200008A699),
|
||||
"Solaris Reserved 2");
|
||||
AddType(0xbf08, UINT64_C(0x11B21DD26A980767), UINT64_C(0x316673200008A699),
|
||||
"Solaris Reserved 3");
|
||||
AddType(0xbf09, UINT64_C(0x11B21DD26A96237F), UINT64_C(0x316673200008A699),
|
||||
"Solaris Reserved 4");
|
||||
AddType(0xbf0a, UINT64_C(0x11B21DD26A8D2AC7), UINT64_C(0x316673200008A699),
|
||||
"Solaris Reserved 5");
|
||||
|
||||
// I can find no MBR equivalents for these, but they're on the
|
||||
// Wikipedia page for GPT, so here we go....
|
||||
AddType(0xc001, UINT64_C(0x11D33AEB75894C1E), UINT64_C(0x000000A0037BC1B7),
|
||||
"HP-UX data");
|
||||
AddType(0xc002, UINT64_C(0x11D632E3E2A1E728), UINT64_C(0x000000A0037B82A6),
|
||||
"HP-UX service");
|
||||
|
||||
// EFI system and related partitions
|
||||
AddType(0xEF00, UINT64_C(0x11d2f81fc12a7328), UINT64_C(0x3bc93ec9a0004bba),
|
||||
"EFI System"); // EFI System (parted marks Linux boot
|
||||
// partitions like this)
|
||||
AddType(0xEF01, UINT64_C(0x11d333e7024dee41), UINT64_C(0x9FF381C70800699d),
|
||||
"MBR partition scheme"); // Whatever that is (from Wikipedia)
|
||||
AddType(0xEF02, UINT64_C(0x6E6F644921686148), UINT64_C(0x4946456465654E74),
|
||||
"BIOS boot partition"); //
|
||||
|
||||
// A straggler Linux partition type....
|
||||
AddType(0xfd00, UINT64_C(0x4D3B05FCA19D880F), UINT64_C(0x1E91840F3F7406A0),
|
||||
"Linux RAID"); // Linux RAID
|
||||
} // if
|
||||
} // default constructor
|
||||
|
||||
PartTypes::~PartTypes(void) {
|
||||
AType* tempType;
|
||||
|
||||
numInstances--;
|
||||
if (numInstances == 0) {
|
||||
while (allTypes != NULL) {
|
||||
tempType = allTypes;
|
||||
allTypes = allTypes->next;
|
||||
delete tempType;
|
||||
} // while
|
||||
} // if
|
||||
} // destructor
|
||||
|
||||
// Add a single type to the linked list of types. Returns 1 if operation
|
||||
// succeeds, 0 otherwise
|
||||
int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
|
||||
const char* n, int toDisplay) {
|
||||
AType* tempType;
|
||||
int allOK = 1;
|
||||
|
||||
tempType = new AType;
|
||||
if (tempType != NULL) {
|
||||
tempType->MBRType = mbrType;
|
||||
tempType->GUIDType.data1 = guidData1;
|
||||
tempType->GUIDType.data2 = guidData2;
|
||||
strncpy(tempType->name, n, PNAME_SIZE);
|
||||
tempType->display = toDisplay;
|
||||
tempType->next = NULL;
|
||||
if (allTypes == NULL) { // first entry
|
||||
allTypes = tempType;
|
||||
} else {
|
||||
lastType->next = tempType;
|
||||
} // if/else
|
||||
lastType = tempType;
|
||||
} else {
|
||||
allOK = 0;
|
||||
} // if/else
|
||||
return allOK;
|
||||
} // PartTypes::AddType()
|
||||
|
||||
// Displays the available types and my extended MBR codes for same....
|
||||
// Note: This function assumes an 80-column display. On wider displays,
|
||||
// it stops at under 80 columns; on narrower displays, lines will wrap
|
||||
// in an ugly way.
|
||||
void PartTypes::ShowTypes(void) {
|
||||
int colCount = 1; // column count
|
||||
AType* thisType = allTypes;
|
||||
char tempStr[20];
|
||||
|
||||
while (thisType != NULL) {
|
||||
if (thisType->display == 1) { // show it
|
||||
strncpy(tempStr, thisType->name, 19);
|
||||
tempStr[19] = '\0';
|
||||
printf("%04x %-19s ", thisType->MBRType, tempStr);
|
||||
if ((colCount % 3) == 0)
|
||||
printf("\n");
|
||||
colCount++;
|
||||
} // if
|
||||
thisType = thisType->next;
|
||||
} // while
|
||||
printf("\n");
|
||||
} // PartTypes::ShowTypes()
|
||||
|
||||
// Returns 1 if code is a valid extended MBR code, 0 if it's not
|
||||
int PartTypes::Valid(uint16_t code) {
|
||||
AType* thisType = allTypes;
|
||||
int found = 0;
|
||||
|
||||
while ((thisType != NULL) && (!found)) {
|
||||
if (thisType->MBRType == code) {
|
||||
found = 1;
|
||||
} // if
|
||||
thisType = thisType->next;
|
||||
} // while
|
||||
return found;
|
||||
} // PartTypes::Valid()
|
||||
|
||||
// Convert a GUID code to a name.
|
||||
char* PartTypes::GUIDToName(struct GUIDData typeCode, char typeName[]) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if ((theItem->GUIDType.data1 == typeCode.data1) &&
|
||||
(theItem->GUIDType.data2 == typeCode.data2)) { // found it!
|
||||
strcpy(typeName, theItem->name);
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
strcpy(typeName, (char*) "Unknown");
|
||||
} // if (!found)
|
||||
return typeName;
|
||||
} // PartTypes::GUIDToName()
|
||||
|
||||
// This function takes a variant of the MBR partition type code and
|
||||
// converts it to a GUID type code
|
||||
struct GUIDData PartTypes::IDToGUID(uint16_t ID) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
struct GUIDData theGUID;
|
||||
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if (theItem->MBRType == ID) { // found it!
|
||||
theGUID = theItem->GUIDType;
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
theGUID = IDToGUID(0x0700); // assign a default type code
|
||||
printf("Exact type match not found; assigning type code for 'Linux/Windows data'\n");
|
||||
} // if (!found)
|
||||
return theGUID;
|
||||
} // PartTypes::IDToGUID()
|
||||
|
||||
// Convert a GUID to a 16-bit variant of the MBR ID number.
|
||||
// Note that this function ignores entries for which the display variable
|
||||
// is set to 0. This enables control of which values get returned when
|
||||
// there are multiple possibilities, but opens the algorithm up to the
|
||||
// potential for problems should the data in the list be bad.
|
||||
uint16_t PartTypes::GUIDToID(struct GUIDData typeCode) {
|
||||
AType* theItem = allTypes;
|
||||
int found = 0;
|
||||
uint16_t theID;
|
||||
|
||||
while ((theItem != NULL) && (!found)) {
|
||||
if ((theItem->GUIDType.data1 == typeCode.data1) &&
|
||||
(theItem->GUIDType.data2 == typeCode.data2) &&
|
||||
(theItem->display == 1)) { // found it!
|
||||
theID = theItem->MBRType;
|
||||
found = 1;
|
||||
} else {
|
||||
theItem = theItem->next;
|
||||
} // if/else
|
||||
} // while
|
||||
if (!found) {
|
||||
theID = 0xFFFF;
|
||||
} // if (!found)
|
||||
return theID;
|
||||
} // PartTypes::GUIDToID()
|
||||
44
parttypes.h
Normal file
44
parttypes.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string>
|
||||
#include "support.h"
|
||||
|
||||
#ifndef __PARTITION_TYPES
|
||||
#define __PARTITION_TYPES
|
||||
|
||||
// Set the size of the name string
|
||||
#define PNAME_SIZE 80
|
||||
|
||||
using namespace std;
|
||||
|
||||
// A partition type
|
||||
struct AType {
|
||||
// I'm using a custom 16-bit extension of the original MBR 8-bit
|
||||
// type codes, so as to permit disambiguation and use of new
|
||||
// codes required by GPT
|
||||
uint16_t MBRType;
|
||||
struct GUIDData GUIDType;
|
||||
char name[PNAME_SIZE];
|
||||
int display; // 1 to show to users as available type, 0 not to
|
||||
AType* next;
|
||||
}; // struct AType
|
||||
|
||||
class PartTypes {
|
||||
protected:
|
||||
static int numInstances;
|
||||
static AType* allTypes; // Linked list holding all the data
|
||||
static AType* lastType; // Pointer to last entry in the list
|
||||
public:
|
||||
PartTypes(void);
|
||||
~PartTypes(void);
|
||||
int AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2,
|
||||
const char* name, int toDisplay = 1);
|
||||
void ShowTypes(void);
|
||||
int Valid(uint16_t);
|
||||
char* GUIDToName(struct GUIDData typeCode, char typeName[]);
|
||||
struct GUIDData IDToGUID(uint16_t ID);
|
||||
uint16_t GUIDToID(struct GUIDData);
|
||||
};
|
||||
|
||||
#endif
|
||||
354
support.cc
Normal file
354
support.cc
Normal file
@@ -0,0 +1,354 @@
|
||||
// support.cc
|
||||
// Non-class support functions for gdisk program.
|
||||
// Primarily by Rod Smith, February 2009, but with a few functions
|
||||
// copied from other sources (see attributions below).
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include "support.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Get a numeric value from the user, between low and high (inclusive).
|
||||
// Keeps looping until the user enters a value within that range.
|
||||
// If user provides no input, def (default value) is returned.
|
||||
// (If def is outside of the low-high range, an explicit response
|
||||
// is required.)
|
||||
int GetNumber(int low, int high, int def, const char prompt[]) {
|
||||
int response, num;
|
||||
char line[255];
|
||||
|
||||
if (low != high) { // bother only if low and high differ...
|
||||
response = low - 1; // force one loop by setting response outside range
|
||||
while ((response < low) || (response > high)) {
|
||||
printf(prompt);
|
||||
fgets(line, 255, stdin);
|
||||
num = sscanf(line, "%d", &response);
|
||||
if (num == 1) { // user provided a response
|
||||
if ((response < low) || (response > high))
|
||||
printf("Value out of range\n");
|
||||
} else { // user hit enter; return default
|
||||
response = def;
|
||||
} // if/else
|
||||
} // while
|
||||
} else { // low == high, so return this value
|
||||
printf("Using %d\n", low);
|
||||
response = low;
|
||||
} // else
|
||||
return (response);
|
||||
} // GetNumber()
|
||||
|
||||
// Gets a Y/N response (and converts lowercase to uppercase)
|
||||
char GetYN(void) {
|
||||
char line[255];
|
||||
char response = '\0';
|
||||
|
||||
while ((response != 'Y') && (response != 'N')) {
|
||||
printf("(Y/N): ");
|
||||
fgets(line, 255, stdin);
|
||||
sscanf(line, "%c", &response);
|
||||
if (response == 'y') response = 'Y';
|
||||
if (response == 'n') response = 'N';
|
||||
} // while
|
||||
return response;
|
||||
} // GetYN(void)
|
||||
|
||||
// Obtains the final sector number, between low and high, from the
|
||||
// user, accepting values prefixed by "+" to add sectors to low,
|
||||
// or the same with "K", "M", "G", or "T" as suffixes to add
|
||||
// kilobytes, megabytes, gigabytes, or terabytes, respectively.
|
||||
// Use the high value as the default if the user just hits Enter
|
||||
uint64_t GetLastSector(uint64_t low, uint64_t high, char prompt[]) {
|
||||
unsigned long long response;
|
||||
int num;
|
||||
int plusFlag = 0;
|
||||
uint64_t mult = 1;
|
||||
char suffix;
|
||||
char line[255];
|
||||
|
||||
response = low - 1; // Ensure one pass by setting a too-low initial value
|
||||
while ((response < low) || (response > high)) {
|
||||
printf(prompt);
|
||||
fgets(line, 255, stdin);
|
||||
|
||||
// Remove leading spaces, if present
|
||||
while (line[0] == ' ')
|
||||
strcpy(line, &line[1]);
|
||||
|
||||
// If present, flag and remove leading plus sign
|
||||
if (line[0] == '+') {
|
||||
plusFlag = 1;
|
||||
strcpy(line, &line[1]);
|
||||
} // if
|
||||
|
||||
// Extract numeric response and, if present, suffix
|
||||
num = sscanf(line, "%llu%c", &response, &suffix);
|
||||
|
||||
// If no response, use default: The high value
|
||||
if (num <= 0) {
|
||||
response = (unsigned long long) high;
|
||||
suffix = ' ';
|
||||
} // if
|
||||
|
||||
// Set multiplier based on suffix
|
||||
switch (suffix) {
|
||||
case 'K':
|
||||
case 'k':
|
||||
mult = (uint64_t) 1024 / SECTOR_SIZE;
|
||||
break;
|
||||
case 'M':
|
||||
case 'm':
|
||||
mult = (uint64_t) 1048576 / SECTOR_SIZE;
|
||||
break;
|
||||
case 'G':
|
||||
case 'g':
|
||||
mult = (uint64_t) 1073741824 / SECTOR_SIZE;
|
||||
break;
|
||||
case 'T':
|
||||
case 't':
|
||||
mult = ((uint64_t) 1073741824 * (uint64_t) 1024) / (uint64_t) SECTOR_SIZE;
|
||||
break;
|
||||
default:
|
||||
mult = 1;
|
||||
} // switch
|
||||
|
||||
// Adjust response based on multiplier and plus flag, if present
|
||||
response *= (unsigned long long) mult;
|
||||
if (plusFlag == 1) {
|
||||
response = response + (unsigned long long) low - 1;
|
||||
} // if/else
|
||||
} // while
|
||||
return ((uint64_t) response);
|
||||
} // GetLastSector()
|
||||
|
||||
// Return a plain-text name for a partition type.
|
||||
// Takes a size in bytes (in size) and converts this to a size in
|
||||
// SI units (KiB, MiB, GiB, TiB, or PiB), returned in C++ string
|
||||
// form
|
||||
char* BytesToSI(uint64_t size, char theValue[]) {
|
||||
char units[8];
|
||||
float sizeInSI;
|
||||
|
||||
if (theValue != NULL) {
|
||||
sizeInSI = (float) size;
|
||||
strcpy (units, " bytes");
|
||||
if (sizeInSI > 1024.0) {
|
||||
sizeInSI /= 1024.0;
|
||||
strcpy(units, " KiB");
|
||||
} // if
|
||||
if (sizeInSI > 1024.0) {
|
||||
sizeInSI /= 1024.0;
|
||||
strcpy(units, " MiB");
|
||||
} // if
|
||||
if (sizeInSI > 1024.0) {
|
||||
sizeInSI /= 1024.0;
|
||||
strcpy(units, " GiB");
|
||||
} // if
|
||||
if (sizeInSI > 1024.0) {
|
||||
sizeInSI /= 1024.0;
|
||||
strcpy(units, " TiB");
|
||||
} // if
|
||||
if (sizeInSI > 1024.0) {
|
||||
sizeInSI /= 1024.0;
|
||||
strcpy(units, " PiB");
|
||||
} // if
|
||||
if (strcmp(units, " bytes") == 0) { // in bytes, so no decimal point
|
||||
sprintf(theValue, "%1.0f%s", sizeInSI, units);
|
||||
} else {
|
||||
sprintf(theValue, "%1.1f%s", sizeInSI, units);
|
||||
} // if/else
|
||||
} // if
|
||||
return theValue;
|
||||
} // BlocksToSI()
|
||||
|
||||
// Returns block size of device pointed to by fd file descriptor, or -1
|
||||
// if there's a problem
|
||||
int GetBlockSize(int fd) {
|
||||
int err, result;
|
||||
|
||||
#ifdef __APPLE__
|
||||
err = ioctl(fd, DKIOCGETBLOCKSIZE, &result);
|
||||
#else
|
||||
err = ioctl(fd, BLKSSZGET, &result);
|
||||
#endif
|
||||
|
||||
if (result != 512) {
|
||||
printf("\aWARNING! Sector size is not 512 bytes! This program is likely to");
|
||||
printf("misbehave! Proceed at your own risk!\n\n");
|
||||
} // if
|
||||
|
||||
if (err == -1)
|
||||
result = -1;
|
||||
return (result);
|
||||
} // GetBlockSize()
|
||||
|
||||
// Convert a GUID to a string representation, suitable for display
|
||||
// to humans....
|
||||
char* GUIDToStr(struct GUIDData theGUID, char* theString) {
|
||||
uint64_t block;
|
||||
|
||||
if (theString != NULL) {
|
||||
block = (theGUID.data1 & UINT64_C(0x00000000FFFFFFFF));
|
||||
sprintf(theString, "%08llX-", (unsigned long long) block);
|
||||
block = (theGUID.data1 & UINT64_C(0x0000FFFF00000000)) >> 32;
|
||||
sprintf(theString, "%s%04llX-", theString, (unsigned long long) block);
|
||||
block = (theGUID.data1 & UINT64_C(0xFFFF000000000000)) >> 48;
|
||||
sprintf(theString, "%s%04llX-", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x00000000000000FF));
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x000000000000FF00)) >> 8;
|
||||
sprintf(theString, "%s%02llX-", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x0000000000FF0000)) >> 16;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x00000000FF000000)) >> 24;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x000000FF00000000)) >> 32;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x0000FF0000000000)) >> 40;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0x00FF000000000000)) >> 48;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
block = (theGUID.data2 & UINT64_C(0xFF00000000000000)) >> 56;
|
||||
sprintf(theString, "%s%02llX", theString, (unsigned long long) block);
|
||||
} // if
|
||||
return theString;
|
||||
} // GUIDToStr()
|
||||
|
||||
// Get a GUID from the user
|
||||
GUIDData GetGUID(void) {
|
||||
uint64_t part1, part2, part3, part4, part5;
|
||||
int entered = 0;
|
||||
char temp[255], temp2[255];
|
||||
GUIDData theGUID;
|
||||
|
||||
printf("\nA GUID is entered in five segments of from two to six bytes, with\n"
|
||||
"dashes between segments.\n");
|
||||
printf("Enter the entire GUID, a four-byte hexadecimal number for the first segment, or\n"
|
||||
"'R' to generate the entire GUID randomly: ");
|
||||
fgets(temp, 255, stdin);
|
||||
|
||||
// If user entered 'r' or 'R', generate GUID randomly....
|
||||
if ((temp[0] == 'r') || (temp[0] == 'R')) {
|
||||
theGUID.data1 = (uint64_t) rand() * (uint64_t) rand();
|
||||
theGUID.data2 = (uint64_t) rand() * (uint64_t) rand();
|
||||
entered = 1;
|
||||
} // if user entered 'R' or 'r'
|
||||
|
||||
// If string length is right for whole entry, try to parse it....
|
||||
if ((strlen(temp) == 37) && (entered == 0)) {
|
||||
strncpy(temp2, &temp[0], 8);
|
||||
temp2[8] = '\0';
|
||||
sscanf(temp2, "%llx", &part1);
|
||||
strncpy(temp2, &temp[9], 4);
|
||||
temp2[4] = '\0';
|
||||
sscanf(temp2, "%llx", &part2);
|
||||
strncpy(temp2, &temp[14], 4);
|
||||
temp2[4] = '\0';
|
||||
sscanf(temp2, "%llx", &part3);
|
||||
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
|
||||
strncpy(temp2, &temp[19], 4);
|
||||
temp2[4] = '\0';
|
||||
sscanf(temp2, "%llx", &part4);
|
||||
strncpy(temp2, &temp[24], 12);
|
||||
temp2[12] = '\0';
|
||||
sscanf(temp2, "%llx", &part5);
|
||||
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
|
||||
((part4 & UINT64_C(0x00000000000000FF)) << 8) +
|
||||
((part5 & UINT64_C(0x0000FF0000000000)) >> 24) +
|
||||
((part5 & UINT64_C(0x000000FF00000000)) >> 8) +
|
||||
((part5 & UINT64_C(0x00000000FF000000)) << 8) +
|
||||
((part5 & UINT64_C(0x0000000000FF0000)) << 24) +
|
||||
((part5 & UINT64_C(0x000000000000FF00)) << 40) +
|
||||
((part5 & UINT64_C(0x00000000000000FF)) << 56);
|
||||
entered = 1;
|
||||
} // if
|
||||
|
||||
// If neither of the above methods of entry was used, use prompted
|
||||
// entry....
|
||||
if (entered == 0) {
|
||||
sscanf(temp, "%llx", &part1);
|
||||
printf("Enter a two-byte hexadecimal number for the second segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part2);
|
||||
printf("Enter a two-byte hexadecimal number for the third segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part3);
|
||||
theGUID.data1 = (part3 << 48) + (part2 << 32) + part1;
|
||||
printf("Enter a two-byte hexadecimal number for the fourth segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part4);
|
||||
printf("Enter a six-byte hexadecimal number for the fifth segment: ");
|
||||
fgets(temp, 255, stdin);
|
||||
sscanf(temp, "%llx", &part5);
|
||||
theGUID.data2 = ((part4 & UINT64_C(0x000000000000FF00)) >> 8) +
|
||||
((part4 & UINT64_C(0x00000000000000FF)) << 8) +
|
||||
((part5 & UINT64_C(0x0000FF0000000000)) >> 24) +
|
||||
((part5 & UINT64_C(0x000000FF00000000)) >> 8) +
|
||||
((part5 & UINT64_C(0x00000000FF000000)) << 8) +
|
||||
((part5 & UINT64_C(0x0000000000FF0000)) << 24) +
|
||||
((part5 & UINT64_C(0x000000000000FF00)) << 40) +
|
||||
((part5 & UINT64_C(0x00000000000000FF)) << 56);
|
||||
entered = 1;
|
||||
} // if/else
|
||||
printf("New GUID: %s\n", GUIDToStr(theGUID, temp));
|
||||
return theGUID;
|
||||
} // GetGUID()
|
||||
|
||||
// Compute (2 ^ value). Given the return type, value must be 63 or less.
|
||||
// Used in some bit-fiddling functions
|
||||
uint64_t PowerOf2(int value) {
|
||||
uint64_t retval = 1;
|
||||
int i;
|
||||
|
||||
if ((value < 64) && (value >= 0)) {
|
||||
for (i = 0; i < value; i++) {
|
||||
retval *= 2;
|
||||
} // for
|
||||
} else retval = 0;
|
||||
return retval;
|
||||
} // PowerOf2()
|
||||
|
||||
/**************************************************************************************
|
||||
* *
|
||||
* Below functions are lifted from various sources, as documented in comments before *
|
||||
* each one. *
|
||||
* *
|
||||
**************************************************************************************/
|
||||
|
||||
// The disksize function is taken from the Linux fdisk code and modified
|
||||
// to work around a problem returning a uint64_t value on Mac OS.
|
||||
uint64_t disksize(int fd, int *err) {
|
||||
long sz; // Do not delete; needed for Linux
|
||||
long long b; // Do not delete; needed for Linux
|
||||
uint64_t sectors;
|
||||
|
||||
// Note to self: I recall testing a simplified version of
|
||||
// this code, similar to what's in the __APPLE__ block,
|
||||
// on Linux, but I had some problems. IIRC, it ran OK on 32-bit
|
||||
// systems but not on 64-bit. Keep this in mind in case of
|
||||
// 32/64-bit issues on MacOS....
|
||||
#ifdef __APPLE__
|
||||
*err = ioctl(fd, DKIOCGETBLOCKCOUNT, §ors);
|
||||
#else
|
||||
*err = ioctl(fd, BLKGETSIZE, &sz);
|
||||
if (*err) {
|
||||
sz = 0;
|
||||
if (errno != EFBIG)
|
||||
return sz;
|
||||
}
|
||||
*err = ioctl(fd, BLKGETSIZE64, &b);
|
||||
if (*err || b == 0 || b == sz)
|
||||
sectors = sz;
|
||||
else
|
||||
sectors = (b >> 9);
|
||||
#endif
|
||||
return sectors;
|
||||
}
|
||||
42
support.h
Normal file
42
support.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
|
||||
#include <sys/disk.h>
|
||||
#define lseek64 lseek
|
||||
#else
|
||||
|
||||
// Linux only....
|
||||
#include <linux/fs.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef __GPTSUPPORT
|
||||
#define __GPTSUPPORT
|
||||
|
||||
// Set this as a default
|
||||
#define SECTOR_SIZE UINT32_C(512)
|
||||
|
||||
using namespace std;
|
||||
|
||||
// a GUID
|
||||
struct GUIDData {
|
||||
uint64_t data1;
|
||||
uint64_t data2;
|
||||
}; // struct GUIDData
|
||||
|
||||
int GetNumber(int low, int high, int def, const char prompt[]);
|
||||
char GetYN(void);
|
||||
uint64_t GetLastSector(uint64_t low, uint64_t high, char prompt[]);
|
||||
char* BytesToSI(uint64_t size, char theValue[]);
|
||||
int GetBlockSize(int fd);
|
||||
char* GUIDToStr(struct GUIDData theGUID, char* theString);
|
||||
GUIDData GetGUID(void);
|
||||
uint64_t PowerOf2(int value);
|
||||
|
||||
uint64_t disksize(int fd, int* err);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user