blob: 63e453d1db6f933a0fe43d6883ae7d0140315d2c [file] [log] [blame]
srs5694a0eb11a2009-08-29 15:00:08 -04001//
2// C++ Implementation: gptpart
3//
4// Description: Class to implement a SINGLE GPT partition
5//
6//
7// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009
8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
srs5694978041c2009-09-21 20:51:47 -040012// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
13// under the terms of the GNU GPL version 2, as detailed in the COPYING file.
srs5694a0eb11a2009-08-29 15:00:08 -040014
15#define __STDC_LIMIT_MACROS
16#define __STDC_CONSTANT_MACROS
17
srs5694a0eb11a2009-08-29 15:00:08 -040018#include <string.h>
srs5694fed16d02010-01-27 23:03:40 -050019#include <stdio.h>
20#include <iostream>
srs5694a0eb11a2009-08-29 15:00:08 -040021#include "gptpart.h"
22#include "attributes.h"
23
24using namespace std;
25
srs5694a0eb11a2009-08-29 15:00:08 -040026GPTPart::GPTPart(void) {
srs569455d92612010-03-07 22:16:07 -050027 partitionType.Zero();
28 uniqueGUID.Zero();
29 firstLBA = 0;
30 lastLBA = 0;
31 attributes = 0;
srs569464cbd172011-03-01 22:03:54 -050032 memset(name, 0, NAME_SIZE);
srs5694a0eb11a2009-08-29 15:00:08 -040033} // Default constructor
34
35GPTPart::~GPTPart(void) {
36} // destructor
37
srs5694a0eb11a2009-08-29 15:00:08 -040038// Return the gdisk-specific two-byte hex code for the partition
39uint16_t GPTPart::GetHexType(void) {
srs56946699b012010-02-04 00:55:30 -050040 return partitionType.GetHexType();
srs5694a0eb11a2009-08-29 15:00:08 -040041} // GPTPart::GetHexType()
42
43// Return a plain-text description of the partition type (e.g., "Linux/Windows
44// data" or "Linux swap").
srs56946699b012010-02-04 00:55:30 -050045string GPTPart::GetTypeName(void) {
46 return partitionType.TypeName();
srs5694a0eb11a2009-08-29 15:00:08 -040047} // GPTPart::GetNameType()
48
49// Compute and return the partition's length (or 0 if the end is incorrectly
50// set before the beginning).
51uint64_t GPTPart::GetLengthLBA(void) {
52 uint64_t length = 0;
srs569455d92612010-03-07 22:16:07 -050053
srs5694a0eb11a2009-08-29 15:00:08 -040054 if (firstLBA <= lastLBA)
55 length = lastLBA - firstLBA + UINT64_C(1);
56 return length;
57} // GPTPart::GetLengthLBA()
58
srs56940a697312010-01-28 21:10:52 -050059// Return partition's name field, converted to a C++ ASCII string
srs56946699b012010-02-04 00:55:30 -050060string GPTPart::GetDescription(void) {
srs56940a697312010-01-28 21:10:52 -050061 string theName;
srs5694a0eb11a2009-08-29 15:00:08 -040062 int i;
63
srs56940a697312010-01-28 21:10:52 -050064 theName = "";
65 for (i = 0; i < NAME_SIZE; i += 2) {
66 if (name[i] != '\0')
67 theName += name[i];
68 } // for
69 return theName;
srs56946699b012010-02-04 00:55:30 -050070} // GPTPart::GetDescription()
srs56940a697312010-01-28 21:10:52 -050071
srs569408bb0da2010-02-19 17:19:55 -050072// Return 1 if the partition is in use
73int GPTPart::IsUsed(void) {
74 return (firstLBA != UINT64_C(0));
75} // GPTPart::IsUsed()
76
srs56940a697312010-01-28 21:10:52 -050077// Set the type code to the specified one. Also changes the partition
78// name *IF* the current name is the generic one for the current partition
79// type.
srs56946699b012010-02-04 00:55:30 -050080void GPTPart::SetType(PartType t) {
81 if (GetDescription() == partitionType.TypeName()) {
82 SetName(t.TypeName());
srs56940a697312010-01-28 21:10:52 -050083 } // if
84 partitionType = t;
85} // GPTPart::SetType()
srs5694a0eb11a2009-08-29 15:00:08 -040086
srs5694a0eb11a2009-08-29 15:00:08 -040087// Set the name for a partition to theName, or prompt for a name if
srs5694fed16d02010-01-27 23:03:40 -050088// theName is empty. Note that theName is a standard C++-style ASCII
srs5694a0eb11a2009-08-29 15:00:08 -040089// string, although the GUID partition definition requires a UTF-16LE
90// string. This function creates a simple-minded copy for this.
srs56940a697312010-01-28 21:10:52 -050091void GPTPart::SetName(const string & theName) {
srs569455d92612010-03-07 22:16:07 -050092 char newName[NAME_SIZE];
srs569464cbd172011-03-01 22:03:54 -050093 size_t i;
srs5694a0eb11a2009-08-29 15:00:08 -040094
srs569464cbd172011-03-01 22:03:54 -050095 // Blank out new name string, so that it will terminate in a null
96 // when data are copied to it....
97 memset(newName, 0, NAME_SIZE);
srs5694a0eb11a2009-08-29 15:00:08 -040098
srs5694fed16d02010-01-27 23:03:40 -050099 if (theName == "") { // No name specified, so get one from the user
100 cout << "Enter name: ";
srs569464cbd172011-03-01 22:03:54 -0500101 if (!fgets(newName, NAME_SIZE / 2 + 1, stdin)) {
102 cerr << "Critical error! Failed fgets() in GPTPart::SetName()!\n";
103 exit(1);
104 }
srs5694a0eb11a2009-08-29 15:00:08 -0400105
106 // Input is likely to include a newline, so remove it....
srs569464cbd172011-03-01 22:03:54 -0500107 i = strlen(newName);
108 if (i && newName[i - 1] == '\n')
109 newName[i - 1] = '\0';
srs5694a0eb11a2009-08-29 15:00:08 -0400110 } else {
srs5694fed16d02010-01-27 23:03:40 -0500111 strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str());
srs5694a0eb11a2009-08-29 15:00:08 -0400112 } // if
113
114 // Copy the C-style ASCII string from newName into a form that the GPT
115 // table will accept....
srs569464cbd172011-03-01 22:03:54 -0500116 memset(name, 0, NAME_SIZE);
117 for (i = 0; i < NAME_SIZE / 2; i++)
118 name[i * 2] = newName[i];
srs5694a0eb11a2009-08-29 15:00:08 -0400119} // GPTPart::SetName()
120
srs56946699b012010-02-04 00:55:30 -0500121// Set the name for the partition based on the current GUID partition type
122// code's associated name
123void GPTPart::SetDefaultDescription(void) {
124 SetName(partitionType.TypeName());
125} // GPTPart::SetDefaultDescription()
126
srs56940a697312010-01-28 21:10:52 -0500127GPTPart & GPTPart::operator=(const GPTPart & orig) {
srs56940a697312010-01-28 21:10:52 -0500128 partitionType = orig.partitionType;
129 uniqueGUID = orig.uniqueGUID;
130 firstLBA = orig.firstLBA;
131 lastLBA = orig.lastLBA;
132 attributes = orig.attributes;
srs569464cbd172011-03-01 22:03:54 -0500133 memcpy(name, orig.name, NAME_SIZE);
srs56940a697312010-01-28 21:10:52 -0500134 return *this;
135} // assignment operator
136
137// Display summary information; does nothing if the partition is empty.
138void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
139 string sizeInSI;
srs569464cbd172011-03-01 22:03:54 -0500140 size_t i;
srs56940a697312010-01-28 21:10:52 -0500141
142 if (firstLBA != 0) {
srs56940873e9d2010-10-07 13:00:45 -0400143 sizeInSI = BytesToSI(lastLBA - firstLBA + 1, blockSize);
srs569408bb0da2010-02-19 17:19:55 -0500144 cout.fill(' ');
srs56940a697312010-01-28 21:10:52 -0500145 cout.width(4);
146 cout << partNum + 1 << " ";
147 cout.width(14);
148 cout << firstLBA << " ";
149 cout.width(14);
150 cout << lastLBA << " ";
srs56940873e9d2010-10-07 13:00:45 -0400151 cout << BytesToSI(lastLBA - firstLBA + 1, blockSize) << " ";
srs569464cbd172011-03-01 22:03:54 -0500152 for (i = 0; i < 10 - sizeInSI.length(); i++)
srs5694cb76c672010-02-11 22:22:22 -0500153 cout << " ";
srs56940a697312010-01-28 21:10:52 -0500154 cout.fill('0');
155 cout.width(4);
156 cout.setf(ios::uppercase);
srs56946699b012010-02-04 00:55:30 -0500157 cout << hex << partitionType.GetHexType() << " " << dec;
srs56940a697312010-01-28 21:10:52 -0500158 cout.fill(' ');
srs56946699b012010-02-04 00:55:30 -0500159 cout << GetDescription().substr(0, 23) << "\n";
srs56940a697312010-01-28 21:10:52 -0500160 cout.fill(' ');
161 } // if
162} // GPTPart::ShowSummary()
163
164// Show detailed partition information. Does nothing if the partition is
165// empty (as determined by firstLBA being 0).
166void GPTPart::ShowDetails(uint32_t blockSize) {
167 uint64_t size;
168
169 if (firstLBA != 0) {
srs56945a081752010-09-24 20:39:41 -0400170 cout << "Partition GUID code: " << partitionType;
srs56946699b012010-02-04 00:55:30 -0500171 cout << " (" << partitionType.TypeName() << ")\n";
srs56945a081752010-09-24 20:39:41 -0400172 cout << "Partition unique GUID: " << uniqueGUID << "\n";
srs56940a697312010-01-28 21:10:52 -0500173
174 cout << "First sector: " << firstLBA << " (at "
srs56940873e9d2010-10-07 13:00:45 -0400175 << BytesToSI(firstLBA, blockSize) << ")\n";
srs56940a697312010-01-28 21:10:52 -0500176 cout << "Last sector: " << lastLBA << " (at "
srs56940873e9d2010-10-07 13:00:45 -0400177 << BytesToSI(lastLBA, blockSize) << ")\n";
srs56940a697312010-01-28 21:10:52 -0500178 size = (lastLBA - firstLBA + 1);
179 cout << "Partition size: " << size << " sectors ("
srs56940873e9d2010-10-07 13:00:45 -0400180 << BytesToSI(size, blockSize) << ")\n";
srs56940a697312010-01-28 21:10:52 -0500181 cout << "Attribute flags: ";
182 cout.fill('0');
183 cout.width(16);
184 cout << hex;
185 cout << attributes << "\n";
186 cout << dec;
srs56946699b012010-02-04 00:55:30 -0500187 cout << "Partition name: " << GetDescription() << "\n";
srs56940a697312010-01-28 21:10:52 -0500188 cout.fill(' ');
189 } // if
190} // GPTPart::ShowDetails()
191
192// Blank (delete) a single partition
193void GPTPart::BlankPartition(void) {
srs56946699b012010-02-04 00:55:30 -0500194 uniqueGUID.Zero();
195 partitionType.Zero();
srs56940a697312010-01-28 21:10:52 -0500196 firstLBA = 0;
197 lastLBA = 0;
198 attributes = 0;
srs569464cbd172011-03-01 22:03:54 -0500199 memset(name, 0, NAME_SIZE);
srs56940a697312010-01-28 21:10:52 -0500200} // GPTPart::BlankPartition
201
202// Returns 1 if the two partitions overlap, 0 if they don't
203int GPTPart::DoTheyOverlap(const GPTPart & other) {
srs56940a697312010-01-28 21:10:52 -0500204 // Don't bother checking unless these are defined (both start and end points
205 // are 0 for undefined partitions, so just check the start points)
srs569464cbd172011-03-01 22:03:54 -0500206// cout << "Entering GPTPart::DoTheyOverlap()\n";
207 return firstLBA && other.firstLBA &&
208 (firstLBA <= other.lastLBA) != (lastLBA < other.firstLBA);
srs56940a697312010-01-28 21:10:52 -0500209} // GPTPart::DoTheyOverlap()
210
211// Reverse the bytes of integral data types; used on big-endian systems.
212void GPTPart::ReversePartBytes(void) {
srs56940a697312010-01-28 21:10:52 -0500213 ReverseBytes(&firstLBA, 8);
214 ReverseBytes(&lastLBA, 8);
215 ReverseBytes(&attributes, 8);
216} // GPTPart::ReverseBytes()
217
218/****************************************
219 * Functions requiring user interaction *
220 ****************************************/
221
srs56946699b012010-02-04 00:55:30 -0500222// Change the type code on the partition. Also changes the name if the original
223// name is the generic one for the partition type.
srs56940a697312010-01-28 21:10:52 -0500224void GPTPart::ChangeType(void) {
225 char line[255];
srs569464cbd172011-03-01 22:03:54 -0500226 int changeName;
srs569482f3f0b2010-09-22 10:50:24 -0400227 PartType tempType = (GUIDData) "00000000-0000-0000-0000-000000000000";
srs56940a697312010-01-28 21:10:52 -0500228
srs569464cbd172011-03-01 22:03:54 -0500229 changeName = (GetDescription() == GetTypeName());
srs569455d92612010-03-07 22:16:07 -0500230
srs56946699b012010-02-04 00:55:30 -0500231 cout << "Current type is '" << GetTypeName() << "'\n";
srs569482f3f0b2010-09-22 10:50:24 -0400232 do {
233 cout << "Hex code or GUID (L to show codes, Enter = 0700): ";
srs569464cbd172011-03-01 22:03:54 -0500234 if (!fgets(line, sizeof(line), stdin)) {
235 cerr << "Critical error! Failed fgets() in GPTPart::ChangeType()!\n";
236 exit(1);
237 } // if
srs569482f3f0b2010-09-22 10:50:24 -0400238 if ((line[0] == 'L') || (line[0] == 'l')) {
srs56946699b012010-02-04 00:55:30 -0500239 partitionType.ShowAllTypes();
srs569482f3f0b2010-09-22 10:50:24 -0400240 } else {
241 if (strlen(line) == 1)
242 tempType = 0x0700;
243 else
244 tempType = line;
245 } // if/else
246 } while (tempType == (GUIDData) "00000000-0000-0000-0000-000000000000");
247 partitionType = tempType;
srs56946699b012010-02-04 00:55:30 -0500248 cout << "Changed type of partition to '" << partitionType.TypeName() << "'\n";
249 if (changeName) {
250 SetDefaultDescription();
251 } // if
srs56940a697312010-01-28 21:10:52 -0500252} // GPTPart::ChangeType()