blob: cea8362566dcd260507cefa728ae025f2ebbe8a7 [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
srs569455d92612010-03-07 22:16:07 -050029 partitionType.Zero();
30 uniqueGUID.Zero();
31 firstLBA = 0;
32 lastLBA = 0;
33 attributes = 0;
34
srs5694978041c2009-09-21 20:51:47 -040035 for (i = 0; i < NAME_SIZE; i++)
36 name[i] = '\0';
srs5694a0eb11a2009-08-29 15:00:08 -040037} // Default constructor
38
39GPTPart::~GPTPart(void) {
40} // destructor
41
srs5694a0eb11a2009-08-29 15:00:08 -040042// Return the gdisk-specific two-byte hex code for the partition
43uint16_t GPTPart::GetHexType(void) {
srs56946699b012010-02-04 00:55:30 -050044 return partitionType.GetHexType();
srs5694a0eb11a2009-08-29 15:00:08 -040045} // GPTPart::GetHexType()
46
47// Return a plain-text description of the partition type (e.g., "Linux/Windows
48// data" or "Linux swap").
srs56946699b012010-02-04 00:55:30 -050049string GPTPart::GetTypeName(void) {
50 return partitionType.TypeName();
srs5694a0eb11a2009-08-29 15:00:08 -040051} // GPTPart::GetNameType()
52
53// Compute and return the partition's length (or 0 if the end is incorrectly
54// set before the beginning).
55uint64_t GPTPart::GetLengthLBA(void) {
56 uint64_t length = 0;
srs569455d92612010-03-07 22:16:07 -050057
srs5694a0eb11a2009-08-29 15:00:08 -040058 if (firstLBA <= lastLBA)
59 length = lastLBA - firstLBA + UINT64_C(1);
60 return length;
61} // GPTPart::GetLengthLBA()
62
srs56940a697312010-01-28 21:10:52 -050063// Return partition's name field, converted to a C++ ASCII string
srs56946699b012010-02-04 00:55:30 -050064string GPTPart::GetDescription(void) {
srs56940a697312010-01-28 21:10:52 -050065 string theName;
srs5694a0eb11a2009-08-29 15:00:08 -040066 int i;
67
srs56940a697312010-01-28 21:10:52 -050068 theName = "";
69 for (i = 0; i < NAME_SIZE; i += 2) {
70 if (name[i] != '\0')
71 theName += name[i];
72 } // for
73 return theName;
srs56946699b012010-02-04 00:55:30 -050074} // GPTPart::GetDescription()
srs56940a697312010-01-28 21:10:52 -050075
srs569408bb0da2010-02-19 17:19:55 -050076// Return 1 if the partition is in use
77int GPTPart::IsUsed(void) {
78 return (firstLBA != UINT64_C(0));
79} // GPTPart::IsUsed()
80
srs56940a697312010-01-28 21:10:52 -050081// Set the type code to the specified one. Also changes the partition
82// name *IF* the current name is the generic one for the current partition
83// type.
srs56946699b012010-02-04 00:55:30 -050084void GPTPart::SetType(PartType t) {
85 if (GetDescription() == partitionType.TypeName()) {
86 SetName(t.TypeName());
srs56940a697312010-01-28 21:10:52 -050087 } // if
88 partitionType = t;
89} // GPTPart::SetType()
srs5694a0eb11a2009-08-29 15:00:08 -040090
srs5694a0eb11a2009-08-29 15:00:08 -040091// Set the name for a partition to theName, or prompt for a name if
srs5694fed16d02010-01-27 23:03:40 -050092// theName is empty. Note that theName is a standard C++-style ASCII
srs5694a0eb11a2009-08-29 15:00:08 -040093// string, although the GUID partition definition requires a UTF-16LE
94// string. This function creates a simple-minded copy for this.
srs56940a697312010-01-28 21:10:52 -050095void GPTPart::SetName(const string & theName) {
srs569455d92612010-03-07 22:16:07 -050096 char newName[NAME_SIZE];
srs5694fed16d02010-01-27 23:03:40 -050097 char *junk;
srs5694a0eb11a2009-08-29 15:00:08 -040098 int i;
99
100 // Blank out new name string, just to be on the safe side....
101 for (i = 0; i < NAME_SIZE; i++)
102 newName[i] = '\0';
103
srs5694fed16d02010-01-27 23:03:40 -0500104 if (theName == "") { // No name specified, so get one from the user
105 cout << "Enter name: ";
srs56945d58fe02010-01-03 20:57:08 -0500106 junk = fgets(newName, NAME_SIZE / 2, stdin);
srs5694a0eb11a2009-08-29 15:00:08 -0400107
108 // Input is likely to include a newline, so remove it....
109 i = strlen(newName);
srs56946699b012010-02-04 00:55:30 -0500110 if ((i > 0) && (i <= NAME_SIZE))
111 if (newName[i - 1] == '\n')
112 newName[i - 1] = '\0';
srs5694a0eb11a2009-08-29 15:00:08 -0400113 } else {
srs5694fed16d02010-01-27 23:03:40 -0500114 strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str());
srs5694a0eb11a2009-08-29 15:00:08 -0400115 } // if
116
117 // Copy the C-style ASCII string from newName into a form that the GPT
118 // table will accept....
119 for (i = 0; i < NAME_SIZE; i++) {
120 if ((i % 2) == 0) {
121 name[i] = newName[(i / 2)];
122 } else {
123 name[i] = '\0';
124 } // if/else
125 } // for
126} // GPTPart::SetName()
127
srs56946699b012010-02-04 00:55:30 -0500128// Set the name for the partition based on the current GUID partition type
129// code's associated name
130void GPTPart::SetDefaultDescription(void) {
131 SetName(partitionType.TypeName());
132} // GPTPart::SetDefaultDescription()
133
srs56940a697312010-01-28 21:10:52 -0500134GPTPart & GPTPart::operator=(const GPTPart & orig) {
135 int i;
136
137 partitionType = orig.partitionType;
138 uniqueGUID = orig.uniqueGUID;
139 firstLBA = orig.firstLBA;
140 lastLBA = orig.lastLBA;
141 attributes = orig.attributes;
142 for (i = 0; i < NAME_SIZE; i++)
143 name[i] = orig.name[i];
144 return *this;
145} // assignment operator
146
147// Display summary information; does nothing if the partition is empty.
148void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
149 string sizeInSI;
150 int i;
151
152 if (firstLBA != 0) {
153 sizeInSI = BytesToSI(blockSize * (lastLBA - firstLBA + 1));
srs569408bb0da2010-02-19 17:19:55 -0500154 cout.fill(' ');
srs56940a697312010-01-28 21:10:52 -0500155 cout.width(4);
156 cout << partNum + 1 << " ";
157 cout.width(14);
158 cout << firstLBA << " ";
159 cout.width(14);
160 cout << lastLBA << " ";
srs5694cb76c672010-02-11 22:22:22 -0500161 cout << BytesToSI(blockSize * (lastLBA - firstLBA + 1)) << " ";
162 for (i = 0; i < 10 - (int) sizeInSI.length(); i++)
163 cout << " ";
srs56940a697312010-01-28 21:10:52 -0500164 cout.fill('0');
165 cout.width(4);
166 cout.setf(ios::uppercase);
srs56946699b012010-02-04 00:55:30 -0500167 cout << hex << partitionType.GetHexType() << " " << dec;
srs56940a697312010-01-28 21:10:52 -0500168 cout.fill(' ');
srs56946699b012010-02-04 00:55:30 -0500169 cout << GetDescription().substr(0, 23) << "\n";
srs56940a697312010-01-28 21:10:52 -0500170 cout.fill(' ');
171 } // if
172} // GPTPart::ShowSummary()
173
174// Show detailed partition information. Does nothing if the partition is
175// empty (as determined by firstLBA being 0).
176void GPTPart::ShowDetails(uint32_t blockSize) {
177 uint64_t size;
178
179 if (firstLBA != 0) {
srs56945a081752010-09-24 20:39:41 -0400180 cout << "Partition GUID code: " << partitionType;
srs56946699b012010-02-04 00:55:30 -0500181 cout << " (" << partitionType.TypeName() << ")\n";
srs56945a081752010-09-24 20:39:41 -0400182 cout << "Partition unique GUID: " << uniqueGUID << "\n";
srs56940a697312010-01-28 21:10:52 -0500183
184 cout << "First sector: " << firstLBA << " (at "
185 << BytesToSI(firstLBA * blockSize) << ")\n";
186 cout << "Last sector: " << lastLBA << " (at "
187 << BytesToSI(lastLBA * blockSize) << ")\n";
188 size = (lastLBA - firstLBA + 1);
189 cout << "Partition size: " << size << " sectors ("
190 << BytesToSI(size * ((uint64_t) blockSize)) << ")\n";
191 cout << "Attribute flags: ";
192 cout.fill('0');
193 cout.width(16);
194 cout << hex;
195 cout << attributes << "\n";
196 cout << dec;
srs56946699b012010-02-04 00:55:30 -0500197 cout << "Partition name: " << GetDescription() << "\n";
srs56940a697312010-01-28 21:10:52 -0500198 cout.fill(' ');
199 } // if
200} // GPTPart::ShowDetails()
201
202// Blank (delete) a single partition
203void GPTPart::BlankPartition(void) {
204 int j;
srs56940a697312010-01-28 21:10:52 -0500205
srs56946699b012010-02-04 00:55:30 -0500206 uniqueGUID.Zero();
207 partitionType.Zero();
srs56940a697312010-01-28 21:10:52 -0500208 firstLBA = 0;
209 lastLBA = 0;
210 attributes = 0;
211 for (j = 0; j < NAME_SIZE; j++)
212 name[j] = '\0';
213} // GPTPart::BlankPartition
214
215// Returns 1 if the two partitions overlap, 0 if they don't
216int GPTPart::DoTheyOverlap(const GPTPart & other) {
217 int theyDo = 0;
218
219 // Don't bother checking unless these are defined (both start and end points
220 // are 0 for undefined partitions, so just check the start points)
221 if ((firstLBA != 0) && (other.firstLBA != 0)) {
222 if ((firstLBA < other.lastLBA) && (lastLBA >= other.firstLBA))
223 theyDo = 1;
224 if ((other.firstLBA < lastLBA) && (other.lastLBA >= firstLBA))
225 theyDo = 1;
226 } // if
227 return (theyDo);
228} // GPTPart::DoTheyOverlap()
229
230// Reverse the bytes of integral data types; used on big-endian systems.
231void GPTPart::ReversePartBytes(void) {
srs56940a697312010-01-28 21:10:52 -0500232 ReverseBytes(&firstLBA, 8);
233 ReverseBytes(&lastLBA, 8);
234 ReverseBytes(&attributes, 8);
235} // GPTPart::ReverseBytes()
236
237/****************************************
238 * Functions requiring user interaction *
239 ****************************************/
240
srs56946699b012010-02-04 00:55:30 -0500241// Change the type code on the partition. Also changes the name if the original
242// name is the generic one for the partition type.
srs56940a697312010-01-28 21:10:52 -0500243void GPTPart::ChangeType(void) {
244 char line[255];
245 char* junk;
srs569482f3f0b2010-09-22 10:50:24 -0400246 unsigned int changeName = 0;
247 PartType tempType = (GUIDData) "00000000-0000-0000-0000-000000000000";
srs56940a697312010-01-28 21:10:52 -0500248
srs56946699b012010-02-04 00:55:30 -0500249 if (GetDescription() == GetTypeName())
srs569482f3f0b2010-09-22 10:50:24 -0400250 changeName = UINT16_C(1);
srs569455d92612010-03-07 22:16:07 -0500251
srs56946699b012010-02-04 00:55:30 -0500252 cout << "Current type is '" << GetTypeName() << "'\n";
srs569482f3f0b2010-09-22 10:50:24 -0400253 do {
254 cout << "Hex code or GUID (L to show codes, Enter = 0700): ";
srs56940a697312010-01-28 21:10:52 -0500255 junk = fgets(line, 255, stdin);
srs569482f3f0b2010-09-22 10:50:24 -0400256 if ((line[0] == 'L') || (line[0] == 'l')) {
srs56946699b012010-02-04 00:55:30 -0500257 partitionType.ShowAllTypes();
srs569482f3f0b2010-09-22 10:50:24 -0400258 } else {
259 if (strlen(line) == 1)
260 tempType = 0x0700;
261 else
262 tempType = line;
263 } // if/else
264 } while (tempType == (GUIDData) "00000000-0000-0000-0000-000000000000");
265 partitionType = tempType;
srs56946699b012010-02-04 00:55:30 -0500266 cout << "Changed type of partition to '" << partitionType.TypeName() << "'\n";
267 if (changeName) {
268 SetDefaultDescription();
269 } // if
srs56940a697312010-01-28 21:10:52 -0500270} // GPTPart::ChangeType()