blob: 283eb3ddcd88d16995f21cf9f9dc7f8994464b23 [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) {
srs5694978041c2009-09-21 20:51:47 -040027 int i;
28
29 for (i = 0; i < NAME_SIZE; i++)
30 name[i] = '\0';
srs5694a0eb11a2009-08-29 15:00:08 -040031} // Default constructor
32
33GPTPart::~GPTPart(void) {
34} // destructor
35
srs5694a0eb11a2009-08-29 15:00:08 -040036// Return the gdisk-specific two-byte hex code for the partition
37uint16_t GPTPart::GetHexType(void) {
srs56946699b012010-02-04 00:55:30 -050038 return partitionType.GetHexType();
srs5694a0eb11a2009-08-29 15:00:08 -040039} // GPTPart::GetHexType()
40
41// Return a plain-text description of the partition type (e.g., "Linux/Windows
42// data" or "Linux swap").
srs56946699b012010-02-04 00:55:30 -050043string GPTPart::GetTypeName(void) {
44 return partitionType.TypeName();
srs5694a0eb11a2009-08-29 15:00:08 -040045} // GPTPart::GetNameType()
46
47// Compute and return the partition's length (or 0 if the end is incorrectly
48// set before the beginning).
49uint64_t GPTPart::GetLengthLBA(void) {
50 uint64_t length = 0;
51 if (firstLBA <= lastLBA)
52 length = lastLBA - firstLBA + UINT64_C(1);
53 return length;
54} // GPTPart::GetLengthLBA()
55
srs56940a697312010-01-28 21:10:52 -050056// Return partition's name field, converted to a C++ ASCII string
srs56946699b012010-02-04 00:55:30 -050057string GPTPart::GetDescription(void) {
srs56940a697312010-01-28 21:10:52 -050058 string theName;
srs5694a0eb11a2009-08-29 15:00:08 -040059 int i;
60
srs56940a697312010-01-28 21:10:52 -050061 theName = "";
62 for (i = 0; i < NAME_SIZE; i += 2) {
63 if (name[i] != '\0')
64 theName += name[i];
65 } // for
66 return theName;
srs56946699b012010-02-04 00:55:30 -050067} // GPTPart::GetDescription()
srs56940a697312010-01-28 21:10:52 -050068
69// Set the type code to the specified one. Also changes the partition
70// name *IF* the current name is the generic one for the current partition
71// type.
srs56946699b012010-02-04 00:55:30 -050072void GPTPart::SetType(PartType t) {
73 if (GetDescription() == partitionType.TypeName()) {
74 SetName(t.TypeName());
srs56940a697312010-01-28 21:10:52 -050075 } // if
76 partitionType = t;
77} // GPTPart::SetType()
srs5694a0eb11a2009-08-29 15:00:08 -040078
srs5694a0eb11a2009-08-29 15:00:08 -040079// Set the name for a partition to theName, or prompt for a name if
srs5694fed16d02010-01-27 23:03:40 -050080// theName is empty. Note that theName is a standard C++-style ASCII
srs5694a0eb11a2009-08-29 15:00:08 -040081// string, although the GUID partition definition requires a UTF-16LE
82// string. This function creates a simple-minded copy for this.
srs56940a697312010-01-28 21:10:52 -050083void GPTPart::SetName(const string & theName) {
srs5694a0eb11a2009-08-29 15:00:08 -040084 char newName[NAME_SIZE]; // New name
srs5694fed16d02010-01-27 23:03:40 -050085 char *junk;
srs5694a0eb11a2009-08-29 15:00:08 -040086 int i;
87
88 // Blank out new name string, just to be on the safe side....
89 for (i = 0; i < NAME_SIZE; i++)
90 newName[i] = '\0';
91
srs5694fed16d02010-01-27 23:03:40 -050092 if (theName == "") { // No name specified, so get one from the user
93 cout << "Enter name: ";
srs56945d58fe02010-01-03 20:57:08 -050094 junk = fgets(newName, NAME_SIZE / 2, stdin);
srs5694a0eb11a2009-08-29 15:00:08 -040095
96 // Input is likely to include a newline, so remove it....
97 i = strlen(newName);
srs56946699b012010-02-04 00:55:30 -050098 if ((i > 0) && (i <= NAME_SIZE))
99 if (newName[i - 1] == '\n')
100 newName[i - 1] = '\0';
srs5694a0eb11a2009-08-29 15:00:08 -0400101 } else {
srs5694fed16d02010-01-27 23:03:40 -0500102 strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str());
srs5694a0eb11a2009-08-29 15:00:08 -0400103 } // if
104
105 // Copy the C-style ASCII string from newName into a form that the GPT
106 // table will accept....
107 for (i = 0; i < NAME_SIZE; i++) {
108 if ((i % 2) == 0) {
109 name[i] = newName[(i / 2)];
110 } else {
111 name[i] = '\0';
112 } // if/else
113 } // for
114} // GPTPart::SetName()
115
srs56946699b012010-02-04 00:55:30 -0500116// Set the name for the partition based on the current GUID partition type
117// code's associated name
118void GPTPart::SetDefaultDescription(void) {
119 SetName(partitionType.TypeName());
120} // GPTPart::SetDefaultDescription()
121
srs56940a697312010-01-28 21:10:52 -0500122GPTPart & GPTPart::operator=(const GPTPart & orig) {
123 int i;
124
125 partitionType = orig.partitionType;
126 uniqueGUID = orig.uniqueGUID;
127 firstLBA = orig.firstLBA;
128 lastLBA = orig.lastLBA;
129 attributes = orig.attributes;
130 for (i = 0; i < NAME_SIZE; i++)
131 name[i] = orig.name[i];
132 return *this;
133} // assignment operator
134
135// Display summary information; does nothing if the partition is empty.
136void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
137 string sizeInSI;
138 int i;
139
140 if (firstLBA != 0) {
141 sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1));
142 cout.width(4);
143 cout << partNum + 1 << " ";
144 cout.width(14);
145 cout << firstLBA << " ";
146 cout.width(14);
147 cout << lastLBA << " ";
srs5694cb76c672010-02-11 22:22:22 -0500148 cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
149 for (i = 0; i < 10 - (int) sizeInSI.length(); i++)
150 cout << " ";
srs56940a697312010-01-28 21:10:52 -0500151 cout.fill('0');
152 cout.width(4);
153 cout.setf(ios::uppercase);
srs56946699b012010-02-04 00:55:30 -0500154 cout << hex << partitionType.GetHexType() << " " << dec;
srs56940a697312010-01-28 21:10:52 -0500155 cout.fill(' ');
srs56946699b012010-02-04 00:55:30 -0500156 cout << GetDescription().substr(0, 23) << "\n";
srs56940a697312010-01-28 21:10:52 -0500157 cout.fill(' ');
158 } // if
159} // GPTPart::ShowSummary()
160
161// Show detailed partition information. Does nothing if the partition is
162// empty (as determined by firstLBA being 0).
163void GPTPart::ShowDetails(uint32_t blockSize) {
164 uint64_t size;
165
166 if (firstLBA != 0) {
srs56946699b012010-02-04 00:55:30 -0500167 cout << "Partition GUID code: " << partitionType.AsString();
168 cout << " (" << partitionType.TypeName() << ")\n";
169 cout << "Partition unique GUID: " << uniqueGUID.AsString() << "\n";
srs56940a697312010-01-28 21:10:52 -0500170
171 cout << "First sector: " << firstLBA << " (at "
172 << BytesToSI(firstLBA * blockSize) << ")\n";
173 cout << "Last sector: " << lastLBA << " (at "
174 << BytesToSI(lastLBA * blockSize) << ")\n";
175 size = (lastLBA - firstLBA + 1);
176 cout << "Partition size: " << size << " sectors ("
177 << BytesToSI(size * ((uint64_t) blockSize)) << ")\n";
178 cout << "Attribute flags: ";
179 cout.fill('0');
180 cout.width(16);
181 cout << hex;
182 cout << attributes << "\n";
183 cout << dec;
srs56946699b012010-02-04 00:55:30 -0500184 cout << "Partition name: " << GetDescription() << "\n";
srs56940a697312010-01-28 21:10:52 -0500185 cout.fill(' ');
186 } // if
187} // GPTPart::ShowDetails()
188
189// Blank (delete) a single partition
190void GPTPart::BlankPartition(void) {
191 int j;
srs56940a697312010-01-28 21:10:52 -0500192
srs56946699b012010-02-04 00:55:30 -0500193 uniqueGUID.Zero();
194 partitionType.Zero();
srs56940a697312010-01-28 21:10:52 -0500195 firstLBA = 0;
196 lastLBA = 0;
197 attributes = 0;
198 for (j = 0; j < NAME_SIZE; j++)
199 name[j] = '\0';
200} // GPTPart::BlankPartition
201
202// Returns 1 if the two partitions overlap, 0 if they don't
203int GPTPart::DoTheyOverlap(const GPTPart & other) {
204 int theyDo = 0;
205
206 // Don't bother checking unless these are defined (both start and end points
207 // are 0 for undefined partitions, so just check the start points)
208 if ((firstLBA != 0) && (other.firstLBA != 0)) {
209 if ((firstLBA < other.lastLBA) && (lastLBA >= other.firstLBA))
210 theyDo = 1;
211 if ((other.firstLBA < lastLBA) && (other.lastLBA >= firstLBA))
212 theyDo = 1;
213 } // if
214 return (theyDo);
215} // GPTPart::DoTheyOverlap()
216
217// Reverse the bytes of integral data types; used on big-endian systems.
218void GPTPart::ReversePartBytes(void) {
srs56946699b012010-02-04 00:55:30 -0500219// partitionType.ReverseGUIDBytes();
220// uniqueGUID.ReverseGUIDBytes();
srs56940a697312010-01-28 21:10:52 -0500221 ReverseBytes(&firstLBA, 8);
222 ReverseBytes(&lastLBA, 8);
223 ReverseBytes(&attributes, 8);
224} // GPTPart::ReverseBytes()
225
226/****************************************
227 * Functions requiring user interaction *
228 ****************************************/
229
srs56946699b012010-02-04 00:55:30 -0500230// Change the type code on the partition. Also changes the name if the original
231// name is the generic one for the partition type.
srs56940a697312010-01-28 21:10:52 -0500232void GPTPart::ChangeType(void) {
233 char line[255];
234 char* junk;
srs56946699b012010-02-04 00:55:30 -0500235 unsigned int typeNum = 0xFFFF, changeName = 0;
srs56940a697312010-01-28 21:10:52 -0500236
srs56946699b012010-02-04 00:55:30 -0500237 if (GetDescription() == GetTypeName())
238 changeName = 1;
239 cout << "Current type is '" << GetTypeName() << "'\n";
240 while ((!partitionType.Valid(typeNum)) && (typeNum != 0)) {
srs56940a697312010-01-28 21:10:52 -0500241 cout << "Hex code (L to show codes, 0 to enter raw code, Enter = 0700): ";
242 junk = fgets(line, 255, stdin);
243 sscanf(line, "%X", &typeNum);
244 if ((line[0] == 'L') || (line[0] == 'l'))
srs56946699b012010-02-04 00:55:30 -0500245 partitionType.ShowAllTypes();
srs56940a697312010-01-28 21:10:52 -0500246 if (line[0] == '\n') {
247 typeNum = 0x0700;
248 } // if
249 } // while
250 if (typeNum != 0) // user entered a code, so convert it
srs56946699b012010-02-04 00:55:30 -0500251 partitionType = typeNum;
srs56940a697312010-01-28 21:10:52 -0500252 else // user wants to enter the GUID directly, so do that
srs56946699b012010-02-04 00:55:30 -0500253 partitionType.GetGUIDFromUser();
254 cout << "Changed type of partition to '" << partitionType.TypeName() << "'\n";
255 if (changeName) {
256 SetDefaultDescription();
257 } // if
srs56940a697312010-01-28 21:10:52 -0500258} // GPTPart::ChangeType()
259
srs5694a0eb11a2009-08-29 15:00:08 -0400260/***********************************
261 * Non-class but related functions *
262 ***********************************/
263
264// Recursive quick sort algorithm for GPT partitions. Note that if there
265// are any empties in the specified range, they'll be sorted to the
266// start, resulting in a sorted set of partitions that begins with
267// partition 2, 3, or higher.
268void QuickSortGPT(GPTPart* partitions, int start, int finish) {
269 uint64_t starterValue; // starting location of median partition
270 int left, right;
271 GPTPart temp;
272
273 left = start;
274 right = finish;
275 starterValue = partitions[(start + finish) / 2].GetFirstLBA();
276 do {
277 while (partitions[left].GetFirstLBA() < starterValue)
278 left++;
279 while (partitions[right].GetFirstLBA() > starterValue)
280 right--;
281 if (left <= right) {
282 temp = partitions[left];
283 partitions[left] = partitions[right];
284 partitions[right] = temp;
285 left++;
286 right--;
287 } // if
288 } while (left <= right);
289 if (start < right) QuickSortGPT(partitions, start, right);
290 if (finish > left) QuickSortGPT(partitions, left, finish);
291} // QuickSortGPT()