Initial git repository creation, version 0.3.1 plus changes

This commit is contained in:
srs5694
2009-08-18 13:16:10 -04:00
commit e7b4ff9317
18 changed files with 4750 additions and 0 deletions

83
CHANGELOG Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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()

1660
gpt.cc Normal file

File diff suppressed because it is too large Load Diff

153
gpt.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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, &sectors);
#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
View 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