blob: c805d751a75d75b3c775ad34d76f31ee2a20e5df [file] [log] [blame]
srs569496312232011-03-12 01:22:42 -05001/*
2 MBRPart class, part of GPT fdisk program family.
3 Copyright (C) 2011 Roderick W. Smith
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18*/
19
20#define __STDC_LIMIT_MACROS
Aurimas Liutikasfcad0602016-05-10 19:16:10 -070021#ifndef __STDC_CONSTANT_MACROS
srs569496312232011-03-12 01:22:42 -050022#define __STDC_CONSTANT_MACROS
Aurimas Liutikasfcad0602016-05-10 19:16:10 -070023#endif
srs569496312232011-03-12 01:22:42 -050024
25#include <stddef.h>
26#include <stdint.h>
27#include <iostream>
28#include "support.h"
29#include "mbrpart.h"
30
31using namespace std;
32
33uint32_t MBRPart::numHeads = MAX_HEADS;
34uint32_t MBRPart::numSecspTrack = MAX_SECSPERTRACK;
35uint64_t MBRPart::diskSize = 0;
36uint32_t MBRPart::blockSize = 512;
37int MBRPart::numInstances = 0;
38
39MBRPart::MBRPart() {
40 int i;
41
42 status = 0;
43 for (i = 0; i < 3; i++) {
44 firstSector[i] = 0;
45 lastSector[i] = 0;
46 } // for
47 partitionType = 0x00;
48 firstLBA = 0;
49 lengthLBA = 0;
50 includeAs = NONE;
51 canBePrimary = 0;
52 canBeLogical = 0;
53 if (numInstances == 0) {
54 numHeads = MAX_HEADS;
55 numSecspTrack = MAX_SECSPERTRACK;
56 diskSize = 0;
57 blockSize = 512;
58 } // if
59 numInstances++;
60}
61
62MBRPart::MBRPart(const MBRPart& orig) {
63 numInstances++;
64 operator=(orig);
65}
66
67MBRPart::~MBRPart() {
68 numInstances--;
69}
70
71MBRPart& MBRPart::operator=(const MBRPart& orig) {
72 int i;
73
74 status = orig.status;
75 for (i = 0; i < 3; i++) {
76 firstSector[i] = orig.firstSector[i];
77 lastSector[i] = orig.lastSector[i];
78 } // for
79 partitionType = orig.partitionType;
80 firstLBA = orig.firstLBA;
81 lengthLBA = orig.lengthLBA;
82 includeAs = orig.includeAs;
83 canBePrimary = orig.canBePrimary;
84 canBeLogical = orig.canBeLogical;
85 return *this;
86} // MBRPart::operator=(const MBRPart& orig)
87
88// Set partition data from packed MBRRecord structure.
89MBRPart& MBRPart::operator=(const struct MBRRecord& orig) {
90 int i;
91
92 status = orig.status;
93 for (i = 0; i < 3; i++) {
94 firstSector[i] = orig.firstSector[i];
95 lastSector[i] = orig.lastSector[i];
96 } // for
97 partitionType = orig.partitionType;
98 firstLBA = orig.firstLBA;
99 lengthLBA = orig.lengthLBA;
100 if (lengthLBA > 0)
101 includeAs = PRIMARY;
102 else
103 includeAs = NONE;
104 return *this;
105} // MBRPart::operator=(const struct MBRRecord& orig)
106
srs5694c2f6e0c2011-03-16 02:42:33 -0400107// Compare the values, and return a bool result.
108// Because this is intended for sorting and a lengthLBA value of 0 denotes
109// a partition that's not in use and so that should be sorted upwards,
110// we return the opposite of the usual arithmetic result when either
111// lengthLBA value is 0.
112bool MBRPart::operator<(const MBRPart &other) const {
113 if (lengthLBA && other.lengthLBA)
114 return (firstLBA < other.firstLBA);
115 else
116 return (other.firstLBA < firstLBA);
117} // operator<()
118
srs569496312232011-03-12 01:22:42 -0500119/**************************************************
120 * *
121 * Set information on partitions or disks without *
122 * interacting with the user.... *
123 * *
124 **************************************************/
125
srs5694a17fe692011-09-10 20:30:20 -0400126void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t ds, uint32_t bs) {
srs569496312232011-03-12 01:22:42 -0500127 numHeads = heads;
128 numSecspTrack = sectors;
srs5694a17fe692011-09-10 20:30:20 -0400129 diskSize = ds;
130 blockSize = bs;
srs569496312232011-03-12 01:22:42 -0500131} // MBRPart::SetGeometry
132
133// Empty the partition (zero out all values).
134void MBRPart::Empty(void) {
135 status = UINT8_C(0);
136 firstSector[0] = UINT8_C(0);
137 firstSector[1] = UINT8_C(0);
138 firstSector[2] = UINT8_C(0);
139 partitionType = UINT8_C(0);
140 lastSector[0] = UINT8_C(0);
141 lastSector[1] = UINT8_C(0);
142 lastSector[2] = UINT8_C(0);
143 firstLBA = UINT32_C(0);
144 lengthLBA = UINT32_C(0);
145 includeAs = NONE;
146} // MBRPart::Empty()
147
148// Sets the type code, but silently refuses to change it to an extended type
149// code.
150// Returns 1 on success, 0 on failure (extended type code)
151int MBRPart::SetType(uint8_t typeCode, int isExtended) {
152 int allOK = 0;
153
154 if ((isExtended == 1) || ((typeCode != 0x05) && (typeCode != 0x0f) && (typeCode != 0x85))) {
155 partitionType = typeCode;
156 allOK = 1;
157 } // if
158 return allOK;
159} // MBRPart::SetType()
160
161void MBRPart::SetStartLBA(uint64_t start) {
162 if (start > UINT32_MAX)
163 cerr << "Partition start out of range! Continuing, but problems now likely!\n";
164 firstLBA = (uint32_t) start;
165 RecomputeCHS();
166} // MBRPart::SetStartLBA()
167
168void MBRPart::SetLengthLBA(uint64_t length) {
169 if (length > UINT32_MAX)
170 cerr << "Partition length out of range! Continuing, but problems now likely!\n";
171 lengthLBA = (uint32_t) length;
172 RecomputeCHS();
173} // MBRPart::SetLengthLBA()
174
175// Set the start point and length of the partition. This function takes LBA
176// values, sets them directly, and sets the CHS values based on the LBA
177// values and the current geometry settings.
178void MBRPart::SetLocation(uint64_t start, uint64_t length) {
srs5694a17fe692011-09-10 20:30:20 -0400179 int validCHS;
180
srs569496312232011-03-12 01:22:42 -0500181 if ((start > UINT32_MAX) || (length > UINT32_MAX)) {
182 cerr << "Partition values out of range in MBRPart::SetLocation()!\n"
183 << "Continuing, but strange problems are now likely!\n";
184 } // if
185 firstLBA = (uint32_t) start;
186 lengthLBA = (uint32_t) length;
srs5694a17fe692011-09-10 20:30:20 -0400187 validCHS = RecomputeCHS();
srs569496312232011-03-12 01:22:42 -0500188
189 // If this is a complete 0xEE protective MBR partition, max out its
190 // CHS last sector value, as per the GPT spec. (Set to 0xffffff,
191 // although the maximum legal MBR value is 0xfeffff, which is
192 // actually what GNU Parted and Apple's Disk Utility use, in
193 // violation of the GPT spec.)
srs5694a17fe692011-09-10 20:30:20 -0400194 if ((partitionType == 0xEE) && (!validCHS) && (firstLBA == 1) &&
195 ((lengthLBA == diskSize - 1) || (lengthLBA == UINT32_MAX))) {
srs569496312232011-03-12 01:22:42 -0500196 lastSector[0] = lastSector[1] = lastSector[2] = 0xFF;
197 } // if
198} // MBRPart::SetLocation()
199
200// Store the MBR data in the packed structure used for disk I/O...
201void MBRPart::StoreInStruct(MBRRecord* theStruct) {
202 int i;
203
204 theStruct->firstLBA = firstLBA;
205 theStruct->lengthLBA = lengthLBA;
206 theStruct->partitionType = partitionType;
207 theStruct->status = status;
208 for (i = 0; i < 3; i++) {
209 theStruct->firstSector[i] = firstSector[i];
210 theStruct->lastSector[i] = lastSector[i];
211 } // for
212} // MBRPart::StoreInStruct()
213
214/**********************************************
215* *
216* Get information on partitions or disks.... *
217* *
218**********************************************/
219
220// Returns the last LBA value. Note that this can theoretically be a 33-bit
221// value, so we return a 64-bit value. If lengthLBA == 0, returns 0, even if
222// firstLBA is non-0.
223uint64_t MBRPart::GetLastLBA(void) const {
224 if (lengthLBA > 0)
225 return (uint64_t) firstLBA + (uint64_t) lengthLBA - UINT64_C(1);
226 else
227 return 0;
228} // MBRPart::GetLastLBA()
229
230// Returns 1 if other overlaps with the current partition, 0 if they don't
231// overlap
232int MBRPart::DoTheyOverlap (const MBRPart& other) {
233 return lengthLBA && other.lengthLBA &&
234 (firstLBA <= other.GetLastLBA()) != (GetLastLBA() < other.firstLBA);
235} // MBRPart::DoTheyOverlap()
236
237/*************************************************
238 * *
239 * Adjust information on partitions or disks.... *
240 * *
241 *************************************************/
242
srs5694a17fe692011-09-10 20:30:20 -0400243// Recompute the CHS values for the start and end points.
244// Returns 1 if both computed values are within the range
245// that can be expressed by that CHS, 0 otherwise.
246int MBRPart::RecomputeCHS(void) {
247 int retval = 1;
248
srs569496312232011-03-12 01:22:42 -0500249 if (lengthLBA > 0) {
srs5694a17fe692011-09-10 20:30:20 -0400250 retval = LBAtoCHS(firstLBA, firstSector);
251 retval *= LBAtoCHS(firstLBA + lengthLBA - 1, lastSector);
srs569496312232011-03-12 01:22:42 -0500252 } // if
srs5694a17fe692011-09-10 20:30:20 -0400253 return retval;
srs569496312232011-03-12 01:22:42 -0500254} // MBRPart::RecomputeCHS()
255
256// Converts 32-bit LBA value to MBR-style CHS value. Returns 1 if conversion
257// was within the range that can be expressed by CHS (including 0, for an
258// empty partition), 0 if the value is outside that range, and -1 if chs is
259// invalid.
260int MBRPart::LBAtoCHS(uint32_t lba, uint8_t * chs) {
261 uint64_t cylinder, head, sector; // all numbered from 0
262 uint64_t remainder;
263 int retval = 1;
264 int done = 0;
265
266 if (chs != NULL) {
267 // Special case: In case of 0 LBA value, zero out CHS values....
268 if (lba == 0) {
269 chs[0] = chs[1] = chs[2] = UINT8_C(0);
270 done = 1;
271 } // if
272 // If LBA value is too large for CHS, max out CHS values....
273 if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
274 chs[0] = 254;
275 chs[1] = chs[2] = 255;
276 done = 1;
277 retval = 0;
278 } // if
279 // If neither of the above applies, compute CHS values....
280 if (!done) {
281 cylinder = lba / (numHeads * numSecspTrack);
282 remainder = lba - (cylinder * numHeads * numSecspTrack);
283 head = remainder / numSecspTrack;
284 remainder -= head * numSecspTrack;
285 sector = remainder;
286 if (head < numHeads)
287 chs[0] = (uint8_t) head;
288 else
289 retval = 0;
290 if (sector < numSecspTrack) {
291 chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
292 chs[2] = (uint8_t) (cylinder & UINT32_C(0xFF));
293 } else {
294 retval = 0;
295 } // if/else
296 } // if value is expressible and non-0
297 } else { // Invalid (NULL) chs pointer
298 retval = -1;
299 } // if CHS pointer valid
300 return (retval);
301} // MBRPart::LBAtoCHS()
302
303// Reverses the byte order, but only if we're on a big-endian platform.
304// Note that most data come in 8-bit structures, so don't need reversing;
305// only the LBA data needs to be reversed....
306void MBRPart::ReverseByteOrder(void) {
307 if (IsLittleEndian() == 0) {
308 ReverseBytes(&firstLBA, 4);
309 ReverseBytes(&lengthLBA, 4);
310 } // if
311} // MBRPart::ReverseByteOrder()
312
313/**************************
314 * *
315 * User I/O functions.... *
316 * *
317 **************************/
318
319// Show MBR data. Should update canBeLogical flags before calling.
320// If isGpt == 1, omits the "can be logical" and "can be primary" columns.
321void MBRPart::ShowData(int isGpt) {
322 char bootCode = ' ';
323
Roderick W. Smith1eea9b02013-07-06 22:52:58 -0400324 if (status & 0x80) // it's bootable
srs569496312232011-03-12 01:22:42 -0500325 bootCode = '*';
326 cout.fill(' ');
327 cout << bootCode << " ";
328 cout.width(13);
329 cout << firstLBA;
330 cout.width(13);
331 cout << GetLastLBA() << " ";
332 switch (includeAs) {
333 case PRIMARY:
334 cout << "primary";
335 break;
336 case LOGICAL:
337 cout << "logical";
338 break;
339 case NONE:
340 cout << "omitted";
341 break;
342 default:
343 cout << "error ";
344 break;
345 } // switch
346 cout.width(7);
347 if (!isGpt) {
348 if (canBeLogical)
349 cout << " Y ";
350 else
351 cout << " ";
352 if (canBePrimary)
353 cout << " Y ";
354 else
355 cout << " ";
356 } // if
357 cout << "0x";
358 cout.width(2);
359 cout.fill('0');
360 cout << hex << (int) partitionType << dec << "\n";
srs5694699941e2011-03-21 21:33:57 -0400361} // MBRPart::ShowData()