blob: 0214f48f2257b153e73a934ccae22d814d4d89d8 [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
21#define __STDC_CONSTANT_MACROS
22
23#include <stddef.h>
24#include <stdint.h>
25#include <iostream>
26#include "support.h"
27#include "mbrpart.h"
28
29using namespace std;
30
31uint32_t MBRPart::numHeads = MAX_HEADS;
32uint32_t MBRPart::numSecspTrack = MAX_SECSPERTRACK;
33uint64_t MBRPart::diskSize = 0;
34uint32_t MBRPart::blockSize = 512;
35int MBRPart::numInstances = 0;
36
37MBRPart::MBRPart() {
38 int i;
39
40 status = 0;
41 for (i = 0; i < 3; i++) {
42 firstSector[i] = 0;
43 lastSector[i] = 0;
44 } // for
45 partitionType = 0x00;
46 firstLBA = 0;
47 lengthLBA = 0;
48 includeAs = NONE;
49 canBePrimary = 0;
50 canBeLogical = 0;
51 if (numInstances == 0) {
52 numHeads = MAX_HEADS;
53 numSecspTrack = MAX_SECSPERTRACK;
54 diskSize = 0;
55 blockSize = 512;
56 } // if
57 numInstances++;
58}
59
60MBRPart::MBRPart(const MBRPart& orig) {
61 numInstances++;
62 operator=(orig);
63}
64
65MBRPart::~MBRPart() {
66 numInstances--;
67}
68
69MBRPart& MBRPart::operator=(const MBRPart& orig) {
70 int i;
71
72 status = orig.status;
73 for (i = 0; i < 3; i++) {
74 firstSector[i] = orig.firstSector[i];
75 lastSector[i] = orig.lastSector[i];
76 } // for
77 partitionType = orig.partitionType;
78 firstLBA = orig.firstLBA;
79 lengthLBA = orig.lengthLBA;
80 includeAs = orig.includeAs;
81 canBePrimary = orig.canBePrimary;
82 canBeLogical = orig.canBeLogical;
83 return *this;
84} // MBRPart::operator=(const MBRPart& orig)
85
86// Set partition data from packed MBRRecord structure.
87MBRPart& MBRPart::operator=(const struct MBRRecord& orig) {
88 int i;
89
90 status = orig.status;
91 for (i = 0; i < 3; i++) {
92 firstSector[i] = orig.firstSector[i];
93 lastSector[i] = orig.lastSector[i];
94 } // for
95 partitionType = orig.partitionType;
96 firstLBA = orig.firstLBA;
97 lengthLBA = orig.lengthLBA;
98 if (lengthLBA > 0)
99 includeAs = PRIMARY;
100 else
101 includeAs = NONE;
102 return *this;
103} // MBRPart::operator=(const struct MBRRecord& orig)
104
105/**************************************************
106 * *
107 * Set information on partitions or disks without *
108 * interacting with the user.... *
109 * *
110 **************************************************/
111
112void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t diskSize,
113 uint32_t blockSize) {
114 numHeads = heads;
115 numSecspTrack = sectors;
116} // MBRPart::SetGeometry
117
118// Empty the partition (zero out all values).
119void MBRPart::Empty(void) {
120 status = UINT8_C(0);
121 firstSector[0] = UINT8_C(0);
122 firstSector[1] = UINT8_C(0);
123 firstSector[2] = UINT8_C(0);
124 partitionType = UINT8_C(0);
125 lastSector[0] = UINT8_C(0);
126 lastSector[1] = UINT8_C(0);
127 lastSector[2] = UINT8_C(0);
128 firstLBA = UINT32_C(0);
129 lengthLBA = UINT32_C(0);
130 includeAs = NONE;
131} // MBRPart::Empty()
132
133// Sets the type code, but silently refuses to change it to an extended type
134// code.
135// Returns 1 on success, 0 on failure (extended type code)
136int MBRPart::SetType(uint8_t typeCode, int isExtended) {
137 int allOK = 0;
138
139 if ((isExtended == 1) || ((typeCode != 0x05) && (typeCode != 0x0f) && (typeCode != 0x85))) {
140 partitionType = typeCode;
141 allOK = 1;
142 } // if
143 return allOK;
144} // MBRPart::SetType()
145
146void MBRPart::SetStartLBA(uint64_t start) {
147 if (start > UINT32_MAX)
148 cerr << "Partition start out of range! Continuing, but problems now likely!\n";
149 firstLBA = (uint32_t) start;
150 RecomputeCHS();
151} // MBRPart::SetStartLBA()
152
153void MBRPart::SetLengthLBA(uint64_t length) {
154 if (length > UINT32_MAX)
155 cerr << "Partition length out of range! Continuing, but problems now likely!\n";
156 lengthLBA = (uint32_t) length;
157 RecomputeCHS();
158} // MBRPart::SetLengthLBA()
159
160// Set the start point and length of the partition. This function takes LBA
161// values, sets them directly, and sets the CHS values based on the LBA
162// values and the current geometry settings.
163void MBRPart::SetLocation(uint64_t start, uint64_t length) {
164 if ((start > UINT32_MAX) || (length > UINT32_MAX)) {
165 cerr << "Partition values out of range in MBRPart::SetLocation()!\n"
166 << "Continuing, but strange problems are now likely!\n";
167 } // if
168 firstLBA = (uint32_t) start;
169 lengthLBA = (uint32_t) length;
170 RecomputeCHS();
171
172 // If this is a complete 0xEE protective MBR partition, max out its
173 // CHS last sector value, as per the GPT spec. (Set to 0xffffff,
174 // although the maximum legal MBR value is 0xfeffff, which is
175 // actually what GNU Parted and Apple's Disk Utility use, in
176 // violation of the GPT spec.)
177 if ((partitionType == 0xEE) && (firstLBA == 1) && (lengthLBA == diskSize - 2)) {
178 lastSector[0] = lastSector[1] = lastSector[2] = 0xFF;
179 } // if
180} // MBRPart::SetLocation()
181
182// Store the MBR data in the packed structure used for disk I/O...
183void MBRPart::StoreInStruct(MBRRecord* theStruct) {
184 int i;
185
186 theStruct->firstLBA = firstLBA;
187 theStruct->lengthLBA = lengthLBA;
188 theStruct->partitionType = partitionType;
189 theStruct->status = status;
190 for (i = 0; i < 3; i++) {
191 theStruct->firstSector[i] = firstSector[i];
192 theStruct->lastSector[i] = lastSector[i];
193 } // for
194} // MBRPart::StoreInStruct()
195
196/**********************************************
197* *
198* Get information on partitions or disks.... *
199* *
200**********************************************/
201
202// Returns the last LBA value. Note that this can theoretically be a 33-bit
203// value, so we return a 64-bit value. If lengthLBA == 0, returns 0, even if
204// firstLBA is non-0.
205uint64_t MBRPart::GetLastLBA(void) const {
206 if (lengthLBA > 0)
207 return (uint64_t) firstLBA + (uint64_t) lengthLBA - UINT64_C(1);
208 else
209 return 0;
210} // MBRPart::GetLastLBA()
211
212// Returns 1 if other overlaps with the current partition, 0 if they don't
213// overlap
214int MBRPart::DoTheyOverlap (const MBRPart& other) {
215 return lengthLBA && other.lengthLBA &&
216 (firstLBA <= other.GetLastLBA()) != (GetLastLBA() < other.firstLBA);
217} // MBRPart::DoTheyOverlap()
218
219/*************************************************
220 * *
221 * Adjust information on partitions or disks.... *
222 * *
223 *************************************************/
224
225void MBRPart::RecomputeCHS(void) {
226 if (lengthLBA > 0) {
227 LBAtoCHS(firstLBA, firstSector);
228 LBAtoCHS(firstLBA + lengthLBA - 1, lastSector);
229 } // if
230} // MBRPart::RecomputeCHS()
231
232// Converts 32-bit LBA value to MBR-style CHS value. Returns 1 if conversion
233// was within the range that can be expressed by CHS (including 0, for an
234// empty partition), 0 if the value is outside that range, and -1 if chs is
235// invalid.
236int MBRPart::LBAtoCHS(uint32_t lba, uint8_t * chs) {
237 uint64_t cylinder, head, sector; // all numbered from 0
238 uint64_t remainder;
239 int retval = 1;
240 int done = 0;
241
242 if (chs != NULL) {
243 // Special case: In case of 0 LBA value, zero out CHS values....
244 if (lba == 0) {
245 chs[0] = chs[1] = chs[2] = UINT8_C(0);
246 done = 1;
247 } // if
248 // If LBA value is too large for CHS, max out CHS values....
249 if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
250 chs[0] = 254;
251 chs[1] = chs[2] = 255;
252 done = 1;
253 retval = 0;
254 } // if
255 // If neither of the above applies, compute CHS values....
256 if (!done) {
257 cylinder = lba / (numHeads * numSecspTrack);
258 remainder = lba - (cylinder * numHeads * numSecspTrack);
259 head = remainder / numSecspTrack;
260 remainder -= head * numSecspTrack;
261 sector = remainder;
262 if (head < numHeads)
263 chs[0] = (uint8_t) head;
264 else
265 retval = 0;
266 if (sector < numSecspTrack) {
267 chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
268 chs[2] = (uint8_t) (cylinder & UINT32_C(0xFF));
269 } else {
270 retval = 0;
271 } // if/else
272 } // if value is expressible and non-0
273 } else { // Invalid (NULL) chs pointer
274 retval = -1;
275 } // if CHS pointer valid
276 return (retval);
277} // MBRPart::LBAtoCHS()
278
279// Reverses the byte order, but only if we're on a big-endian platform.
280// Note that most data come in 8-bit structures, so don't need reversing;
281// only the LBA data needs to be reversed....
282void MBRPart::ReverseByteOrder(void) {
283 if (IsLittleEndian() == 0) {
284 ReverseBytes(&firstLBA, 4);
285 ReverseBytes(&lengthLBA, 4);
286 } // if
287} // MBRPart::ReverseByteOrder()
288
289/**************************
290 * *
291 * User I/O functions.... *
292 * *
293 **************************/
294
295// Show MBR data. Should update canBeLogical flags before calling.
296// If isGpt == 1, omits the "can be logical" and "can be primary" columns.
297void MBRPart::ShowData(int isGpt) {
298 char bootCode = ' ';
299
300 if (status && 0x80) // it's bootable
301 bootCode = '*';
302 cout.fill(' ');
303 cout << bootCode << " ";
304 cout.width(13);
305 cout << firstLBA;
306 cout.width(13);
307 cout << GetLastLBA() << " ";
308 switch (includeAs) {
309 case PRIMARY:
310 cout << "primary";
311 break;
312 case LOGICAL:
313 cout << "logical";
314 break;
315 case NONE:
316 cout << "omitted";
317 break;
318 default:
319 cout << "error ";
320 break;
321 } // switch
322 cout.width(7);
323 if (!isGpt) {
324 if (canBeLogical)
325 cout << " Y ";
326 else
327 cout << " ";
328 if (canBePrimary)
329 cout << " Y ";
330 else
331 cout << " ";
332 } // if
333 cout << "0x";
334 cout.width(2);
335 cout.fill('0');
336 cout << hex << (int) partitionType << dec << "\n";
337} // MBRPart::ShowData()