2 MBRPart class, part of GPT fdisk program family.
3 Copyright (C) 2011 Roderick W. Smith
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.
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.
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.
20 #define __STDC_LIMIT_MACROS
21 #define __STDC_CONSTANT_MACROS
31 uint32_t MBRPart::numHeads = MAX_HEADS;
32 uint32_t MBRPart::numSecspTrack = MAX_SECSPERTRACK;
33 uint64_t MBRPart::diskSize = 0;
34 uint32_t MBRPart::blockSize = 512;
35 int MBRPart::numInstances = 0;
41 for (i = 0; i < 3; i++) {
51 if (numInstances == 0) {
53 numSecspTrack = MAX_SECSPERTRACK;
60 MBRPart::MBRPart(const MBRPart& orig) {
69 MBRPart& MBRPart::operator=(const MBRPart& orig) {
73 for (i = 0; i < 3; i++) {
74 firstSector[i] = orig.firstSector[i];
75 lastSector[i] = orig.lastSector[i];
77 partitionType = orig.partitionType;
78 firstLBA = orig.firstLBA;
79 lengthLBA = orig.lengthLBA;
80 includeAs = orig.includeAs;
81 canBePrimary = orig.canBePrimary;
82 canBeLogical = orig.canBeLogical;
84 } // MBRPart::operator=(const MBRPart& orig)
86 // Set partition data from packed MBRRecord structure.
87 MBRPart& MBRPart::operator=(const struct MBRRecord& orig) {
91 for (i = 0; i < 3; i++) {
92 firstSector[i] = orig.firstSector[i];
93 lastSector[i] = orig.lastSector[i];
95 partitionType = orig.partitionType;
96 firstLBA = orig.firstLBA;
97 lengthLBA = orig.lengthLBA;
103 } // MBRPart::operator=(const struct MBRRecord& orig)
105 // Compare the values, and return a bool result.
106 // Because this is intended for sorting and a lengthLBA value of 0 denotes
107 // a partition that's not in use and so that should be sorted upwards,
108 // we return the opposite of the usual arithmetic result when either
109 // lengthLBA value is 0.
110 bool MBRPart::operator<(const MBRPart &other) const {
111 if (lengthLBA && other.lengthLBA)
112 return (firstLBA < other.firstLBA);
114 return (other.firstLBA < firstLBA);
117 /**************************************************
119 * Set information on partitions or disks without *
120 * interacting with the user.... *
122 **************************************************/
124 void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t ds, uint32_t bs) {
126 numSecspTrack = sectors;
129 } // MBRPart::SetGeometry
131 // Empty the partition (zero out all values).
132 void MBRPart::Empty(void) {
134 firstSector[0] = UINT8_C(0);
135 firstSector[1] = UINT8_C(0);
136 firstSector[2] = UINT8_C(0);
137 partitionType = UINT8_C(0);
138 lastSector[0] = UINT8_C(0);
139 lastSector[1] = UINT8_C(0);
140 lastSector[2] = UINT8_C(0);
141 firstLBA = UINT32_C(0);
142 lengthLBA = UINT32_C(0);
144 } // MBRPart::Empty()
146 // Sets the type code, but silently refuses to change it to an extended type
148 // Returns 1 on success, 0 on failure (extended type code)
149 int MBRPart::SetType(uint8_t typeCode, int isExtended) {
152 if ((isExtended == 1) || ((typeCode != 0x05) && (typeCode != 0x0f) && (typeCode != 0x85))) {
153 partitionType = typeCode;
157 } // MBRPart::SetType()
159 void MBRPart::SetStartLBA(uint64_t start) {
160 if (start > UINT32_MAX)
161 cerr << "Partition start out of range! Continuing, but problems now likely!\n";
162 firstLBA = (uint32_t) start;
164 } // MBRPart::SetStartLBA()
166 void MBRPart::SetLengthLBA(uint64_t length) {
167 if (length > UINT32_MAX)
168 cerr << "Partition length out of range! Continuing, but problems now likely!\n";
169 lengthLBA = (uint32_t) length;
171 } // MBRPart::SetLengthLBA()
173 // Set the start point and length of the partition. This function takes LBA
174 // values, sets them directly, and sets the CHS values based on the LBA
175 // values and the current geometry settings.
176 void MBRPart::SetLocation(uint64_t start, uint64_t length) {
179 if ((start > UINT32_MAX) || (length > UINT32_MAX)) {
180 cerr << "Partition values out of range in MBRPart::SetLocation()!\n"
181 << "Continuing, but strange problems are now likely!\n";
183 firstLBA = (uint32_t) start;
184 lengthLBA = (uint32_t) length;
185 validCHS = RecomputeCHS();
187 // If this is a complete 0xEE protective MBR partition, max out its
188 // CHS last sector value, as per the GPT spec. (Set to 0xffffff,
189 // although the maximum legal MBR value is 0xfeffff, which is
190 // actually what GNU Parted and Apple's Disk Utility use, in
191 // violation of the GPT spec.)
192 if ((partitionType == 0xEE) && (!validCHS) && (firstLBA == 1) &&
193 ((lengthLBA == diskSize - 1) || (lengthLBA == UINT32_MAX))) {
194 lastSector[0] = lastSector[1] = lastSector[2] = 0xFF;
196 } // MBRPart::SetLocation()
198 // Store the MBR data in the packed structure used for disk I/O...
199 void MBRPart::StoreInStruct(MBRRecord* theStruct) {
202 theStruct->firstLBA = firstLBA;
203 theStruct->lengthLBA = lengthLBA;
204 theStruct->partitionType = partitionType;
205 theStruct->status = status;
206 for (i = 0; i < 3; i++) {
207 theStruct->firstSector[i] = firstSector[i];
208 theStruct->lastSector[i] = lastSector[i];
210 } // MBRPart::StoreInStruct()
212 /**********************************************
214 * Get information on partitions or disks.... *
216 **********************************************/
218 // Returns the last LBA value. Note that this can theoretically be a 33-bit
219 // value, so we return a 64-bit value. If lengthLBA == 0, returns 0, even if
220 // firstLBA is non-0.
221 uint64_t MBRPart::GetLastLBA(void) const {
223 return (uint64_t) firstLBA + (uint64_t) lengthLBA - UINT64_C(1);
226 } // MBRPart::GetLastLBA()
228 // Returns 1 if other overlaps with the current partition, 0 if they don't
230 int MBRPart::DoTheyOverlap (const MBRPart& other) {
231 return lengthLBA && other.lengthLBA &&
232 (firstLBA <= other.GetLastLBA()) != (GetLastLBA() < other.firstLBA);
233 } // MBRPart::DoTheyOverlap()
235 /*************************************************
237 * Adjust information on partitions or disks.... *
239 *************************************************/
241 // Recompute the CHS values for the start and end points.
242 // Returns 1 if both computed values are within the range
243 // that can be expressed by that CHS, 0 otherwise.
244 int MBRPart::RecomputeCHS(void) {
248 retval = LBAtoCHS(firstLBA, firstSector);
249 retval *= LBAtoCHS(firstLBA + lengthLBA - 1, lastSector);
252 } // MBRPart::RecomputeCHS()
254 // Converts 32-bit LBA value to MBR-style CHS value. Returns 1 if conversion
255 // was within the range that can be expressed by CHS (including 0, for an
256 // empty partition), 0 if the value is outside that range, and -1 if chs is
258 int MBRPart::LBAtoCHS(uint32_t lba, uint8_t * chs) {
259 uint64_t cylinder, head, sector; // all numbered from 0
265 // Special case: In case of 0 LBA value, zero out CHS values....
267 chs[0] = chs[1] = chs[2] = UINT8_C(0);
270 // If LBA value is too large for CHS, max out CHS values....
271 if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
273 chs[1] = chs[2] = 255;
277 // If neither of the above applies, compute CHS values....
279 cylinder = lba / (numHeads * numSecspTrack);
280 remainder = lba - (cylinder * numHeads * numSecspTrack);
281 head = remainder / numSecspTrack;
282 remainder -= head * numSecspTrack;
285 chs[0] = (uint8_t) head;
288 if (sector < numSecspTrack) {
289 chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
290 chs[2] = (uint8_t) (cylinder & UINT32_C(0xFF));
294 } // if value is expressible and non-0
295 } else { // Invalid (NULL) chs pointer
297 } // if CHS pointer valid
299 } // MBRPart::LBAtoCHS()
301 // Reverses the byte order, but only if we're on a big-endian platform.
302 // Note that most data come in 8-bit structures, so don't need reversing;
303 // only the LBA data needs to be reversed....
304 void MBRPart::ReverseByteOrder(void) {
305 if (IsLittleEndian() == 0) {
306 ReverseBytes(&firstLBA, 4);
307 ReverseBytes(&lengthLBA, 4);
309 } // MBRPart::ReverseByteOrder()
311 /**************************
313 * User I/O functions.... *
315 **************************/
317 // Show MBR data. Should update canBeLogical flags before calling.
318 // If isGpt == 1, omits the "can be logical" and "can be primary" columns.
319 void MBRPart::ShowData(int isGpt) {
322 if (status && 0x80) // it's bootable
325 cout << bootCode << " ";
329 cout << GetLastLBA() << " ";
358 cout << hex << (int) partitionType << dec << "\n";
359 } // MBRPart::ShowData()