1
/* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition
4
/* Initial coding by Rod Smith, January to February, 2009 */
6
/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
7
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
9
#define __STDC_LIMIT_MACROS
10
#define __STDC_CONSTANT_MACROS
26
/****************************************
28
* MBRData class and related structures *
30
****************************************/
32
MBRData::MBRData(void) {
33
blockSize = SECTOR_SIZE;
37
srand((unsigned int) time(NULL));
39
numSecspTrack = MAX_SECSPERTRACK;
41
} // MBRData default constructor
43
MBRData::MBRData(char *filename) {
44
blockSize = SECTOR_SIZE;
46
strcpy(device, filename);
49
numSecspTrack = MAX_SECSPERTRACK;
51
srand((unsigned int) time(NULL));
52
// Try to read the specified partition table, but if it fails....
53
if (!ReadMBRData(filename)) {
57
} // MBRData(char *filename) constructor
59
MBRData::~MBRData(void) {
60
} // MBRData destructor
62
/**********************
64
* Disk I/O functions *
66
**********************/
68
// Read data from MBR. Returns 1 if read was successful (even if the
69
// data isn't a valid MBR), 0 if the read failed.
70
int MBRData::ReadMBRData(char* deviceFilename) {
73
if ((fd = open(deviceFilename, O_RDONLY)) != -1) {
82
strcpy(device, deviceFilename);
85
} // MBRData::ReadMBRData(char* deviceFilename)
87
// Read data from MBR. If checkBlockSize == 1 (the default), the block
88
// size is checked; otherwise it's set to the default (512 bytes).
89
// Note that any extended partition(s) present will be explicitly stored
90
// in the partitions[] array, along with their contained partitions; the
91
// extended container partition(s) should be ignored by other functions.
92
void MBRData::ReadMBRData(int fd, int checkBlockSize) {
93
int allOK = 1, i, j, logicalNum;
97
// Empty existing MBR data, including the logical partitions...
100
err = lseek64(fd, 0, SEEK_SET);
101
err = read(fd, &tempMBR, 512);
102
for (i = 0; i < 440; i++)
103
code[i] = tempMBR.code[i];
104
diskSignature = tempMBR.diskSignature;
105
nulls = tempMBR.nulls;
106
for (i = 0; i < 4; i++) {
107
partitions[i].status = tempMBR.partitions[i].status;
108
partitions[i].partitionType = tempMBR.partitions[i].partitionType;
109
partitions[i].firstLBA = tempMBR.partitions[i].firstLBA;
110
partitions[i].lengthLBA = tempMBR.partitions[i].lengthLBA;
111
for (j = 0; j < 3; j++) {
112
partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
113
partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
114
} // for j... (reading parts of CHS geometry)
115
} // for i... (reading all four partitions)
116
MBRSignature = tempMBR.MBRSignature;
118
// Reverse the byte order, if necessary
119
if (IsLittleEndian() == 0) {
120
ReverseBytes(&diskSignature, 4);
121
ReverseBytes(&nulls, 2);
122
ReverseBytes(&MBRSignature, 2);
123
for (i = 0; i < 4; i++) {
124
ReverseBytes(&partitions[i].firstLBA, 4);
125
ReverseBytes(&partitions[i].lengthLBA, 4);
129
if (MBRSignature != MBR_SIGNATURE) {
135
diskSize = disksize(fd, &err);
138
if (checkBlockSize) {
139
blockSize = GetBlockSize(fd);
140
} // if (checkBlockSize)
142
// Load logical partition data, if any is found....
144
for (i = 0; i < 4; i++) {
145
if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
146
|| (partitions[i].partitionType == 0x85)) {
147
// Found it, so call a recursive algorithm to load everything from them....
148
logicalNum = ReadLogicalPart(fd, partitions[i].firstLBA, UINT32_C(0), 4);
149
if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
151
fprintf(stderr, "Error reading logical partitions! List may be truncated!\n");
152
} // if maxLogicals valid
153
} // if primary partition is extended
154
} // for primary partition loop
155
if (allOK) { // Loaded logicals OK
162
/* Check to see if it's in GPT format.... */
164
for (i = 0; i < 4; i++) {
165
if (partitions[i].partitionType == UINT8_C(0xEE)) {
171
// If there's an EFI GPT partition, look for other partition types,
174
for (i = 0 ; i < 4; i++) {
175
if ((partitions[i].partitionType != UINT8_C(0xEE)) &&
176
(partitions[i].partitionType != UINT8_C(0x00)))
179
} // if (hybrid detection code)
180
} // MBRData::ReadMBRData(int fd)
182
// This is a recursive function to read all the logical partitions, following the
183
// logical partition linked list from the disk and storing the basic data in the
184
// partitions[] array. Returns last index to partitions[] used, or -1 if there was
187
// fd = file descriptor
188
// extendedStart = LBA of the start of the extended partition
189
// diskOffset = LBA offset WITHIN the extended partition of the one to be read
190
// partNum = location in partitions[] array to store retrieved data
191
int MBRData::ReadLogicalPart(int fd, uint32_t extendedStart,
192
uint32_t diskOffset, int partNum) {
196
// Check for a valid partition number. Note that partitions MAY be read into
197
// the area normally used by primary partitions, although the only calling
198
// function as of GPT fdisk version 0.5.0 doesn't do so.
199
if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
200
offset = (off_t) (extendedStart + diskOffset) * blockSize;
201
if (lseek64(fd, offset, SEEK_SET) == (off_t) -1) { // seek to EBR record
202
fprintf(stderr, "Unable to seek to %lu! Aborting!\n", (unsigned long) offset);
205
if (read(fd, &ebr, 512) != 512) { // Load the data....
206
fprintf(stderr, "Error seeking to or reading logical partition data from %lu!\nAborting!\n",
207
(unsigned long) offset);
209
} else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
210
ReverseBytes(&ebr.MBRSignature, 2);
211
ReverseBytes(&ebr.partitions[0].firstLBA, 4);
212
ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
213
ReverseBytes(&ebr.partitions[1].firstLBA, 4);
214
ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
217
if (ebr.MBRSignature != MBR_SIGNATURE) {
219
fprintf(stderr, "MBR signature in logical partition invalid; read 0x%04X, but should be 0x%04X\n",
220
(unsigned int) ebr.MBRSignature, (unsigned int) MBR_SIGNATURE);
223
// Copy over the basic data....
224
partitions[partNum].status = ebr.partitions[0].status;
225
partitions[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
226
partitions[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
227
partitions[partNum].partitionType = ebr.partitions[0].partitionType;
229
// Find the next partition (if there is one) and recurse....
230
if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 4) &&
231
(partNum < (MAX_MBR_PARTS - 1))) {
232
partNum = ReadLogicalPart(fd, extendedStart, ebr.partitions[1].firstLBA,
236
} // if another partition
237
} // Not enough space for all the logicals (or previous error encountered)
239
} // MBRData::ReadLogicalPart()
241
// Write the MBR data to the default defined device. Note that this writes
242
// ONLY the MBR itself, not the logical partition data.
243
int MBRData::WriteMBRData(void) {
246
if ((fd = open(device, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) {
253
} // MBRData::WriteMBRData(void)
255
// Save the MBR data to a file. Note that this function writes ONLY the
256
// MBR data, not the logical partitions (if any are defined).
257
void MBRData::WriteMBRData(int fd) {
261
// Reverse the byte order, if necessary
262
if (IsLittleEndian() == 0) {
263
ReverseBytes(&diskSignature, 4);
264
ReverseBytes(&nulls, 2);
265
ReverseBytes(&MBRSignature, 2);
266
for (i = 0; i < 4; i++) {
267
ReverseBytes(&partitions[i].firstLBA, 4);
268
ReverseBytes(&partitions[i].lengthLBA, 4);
272
// Copy MBR data to a 512-byte data structure for writing, to
273
// work around a FreeBSD limitation....
274
for (i = 0; i < 440; i++)
275
tempMBR.code[i] = code[i];
276
tempMBR.diskSignature = diskSignature;
277
tempMBR.nulls = nulls;
278
tempMBR.MBRSignature = MBRSignature;
279
for (i = 0; i < 4; i++) {
280
tempMBR.partitions[i].status = partitions[i].status;
281
tempMBR.partitions[i].partitionType = partitions[i].partitionType;
282
tempMBR.partitions[i].firstLBA = partitions[i].firstLBA;
283
tempMBR.partitions[i].lengthLBA = partitions[i].lengthLBA;
284
for (j = 0; j < 3; j++) {
285
tempMBR.partitions[i].firstSector[j] = partitions[i].firstSector[j];
286
tempMBR.partitions[i].lastSector[j] = partitions[i].lastSector[j];
290
// Now write that data structure...
291
lseek64(fd, 0, SEEK_SET);
292
write(fd, &tempMBR, 512);
294
// Reverse the byte order back, if necessary
295
if (IsLittleEndian() == 0) {
296
ReverseBytes(&diskSignature, 4);
297
ReverseBytes(&nulls, 2);
298
ReverseBytes(&MBRSignature, 2);
299
for (i = 0; i < 4; i++) {
300
ReverseBytes(&partitions[i].firstLBA, 4);
301
ReverseBytes(&partitions[i].lengthLBA, 4);
304
} // MBRData::WriteMBRData(int fd)
306
/********************************************
308
* Functions that display data for the user *
310
********************************************/
312
// Show the MBR data to the user....
313
void MBRData::DisplayMBRData(void) {
318
printf("MBR disk identifier: 0x%08X\n", (unsigned int) diskSignature);
319
printf("MBR partitions:\n");
320
printf("Number\t Boot\t Start (sector)\t Length (sectors)\tType\n");
321
for (i = 0; i < MAX_MBR_PARTS; i++) {
322
if (partitions[i].lengthLBA != 0) {
323
if (partitions[i].status && 0x80) // it's bootable
327
printf("%4d\t %c\t%13lu\t%15lu \t0x%02X\n", i + 1, bootCode,
328
(unsigned long) partitions[i].firstLBA,
329
(unsigned long) partitions[i].lengthLBA, partitions[i].partitionType);
332
printf("\nDisk size is %llu sectors (%s)\n", (unsigned long long) diskSize,
333
BytesToSI(diskSize * (uint64_t) blockSize, tempStr));
334
} // MBRData::DisplayMBRData()
336
// Displays the state, as a word, on stdout. Used for debugging & to
337
// tell the user about the MBR state when the program launches....
338
void MBRData::ShowState(void) {
341
printf(" MBR: not present\n");
344
printf(" MBR: protective\n");
347
printf(" MBR: hybrid\n");
350
printf(" MBR: MBR only\n");
353
printf("\a MBR: unknown -- bug!\n");
356
} // MBRData::ShowState()
358
/*********************************************************************
360
* Functions that set or get disk metadata (CHS geometry, disk size, *
363
*********************************************************************/
365
// Sets the CHS geometry. CHS geometry is used by LBAtoCHS() function.
366
// Note that this only sets the heads and sectors; the number of
367
// cylinders is determined by these values and the disk size.
368
void MBRData::SetCHSGeom(uint32_t h, uint32_t s) {
369
if ((h <= MAX_HEADS) && (s <= MAX_SECSPERTRACK)) {
373
printf("Warning! Attempt to set invalid CHS geometry!\n");
375
} // MBRData::SetCHSGeom()
377
// Converts 64-bit LBA value to MBR-style CHS value. Returns 1 if conversion
378
// was within the range that can be expressed by CHS (including 0, for an
379
// empty partition), 0 if the value is outside that range, and -1 if chs is
381
int MBRData::LBAtoCHS(uint64_t lba, uint8_t * chs) {
382
uint64_t cylinder, head, sector; // all numbered from 0
388
// Special case: In case of 0 LBA value, zero out CHS values....
390
chs[0] = chs[1] = chs[2] = UINT8_C(0);
393
// If LBA value is too large for CHS, max out CHS values....
394
if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
396
chs[1] = chs[2] = 255;
400
// If neither of the above applies, compute CHS values....
402
cylinder = lba / (uint64_t) (numHeads * numSecspTrack);
403
remainder = lba - (cylinder * numHeads * numSecspTrack);
404
head = remainder / numSecspTrack;
405
remainder -= head * numSecspTrack;
411
if (sector < numSecspTrack) {
412
chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
413
chs[2] = (uint8_t) (cylinder & UINT64_C(0xFF));
417
} // if value is expressible and non-0
418
} else { // Invalid (NULL) chs pointer
420
} // if CHS pointer valid
422
} // MBRData::LBAtoCHS()
424
/*****************************************************
426
* Functions to create, delete, or change partitions *
428
*****************************************************/
430
// Empty all data. Meant mainly for calling by constructors, but it's also
431
// used by the hybrid MBR functions in the GPTData class.
432
void MBRData::EmptyMBR(int clearBootloader) {
435
// Zero out the boot loader section, the disk signature, and the
436
// 2-byte nulls area only if requested to do so. (This is the
438
if (clearBootloader == 1) {
439
for (i = 0; i < 440; i++)
441
diskSignature = (uint32_t) rand();
445
// Blank out the partitions
446
for (i = 0; i < MAX_MBR_PARTS; i++) {
447
partitions[i].status = UINT8_C(0);
448
partitions[i].firstSector[0] = UINT8_C(0);
449
partitions[i].firstSector[1] = UINT8_C(0);
450
partitions[i].firstSector[2] = UINT8_C(0);
451
partitions[i].partitionType = UINT8_C(0);
452
partitions[i].lastSector[0] = UINT8_C(0);
453
partitions[i].lastSector[1] = UINT8_C(0);
454
partitions[i].lastSector[2] = UINT8_C(0);
455
partitions[i].firstLBA = UINT32_C(0);
456
partitions[i].lengthLBA = UINT32_C(0);
458
MBRSignature = MBR_SIGNATURE;
459
} // MBRData::EmptyMBR()
461
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
462
void MBRData::MakeProtectiveMBR(int clearBoot) {
466
// Initialize variables
468
MBRSignature = MBR_SIGNATURE;
470
partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
472
// Write CHS data. This maxes out the use of the disk, as much as
473
// possible -- even to the point of exceeding the capacity of sub-8GB
474
// disks. The EFI spec says to use 0xffffff as the ending value,
475
// although normal MBR disks max out at 0xfeffff. FWIW, both GNU Parted
476
// and Apple's Disk Utility use 0xfeffff, and the latter puts that
477
// value in for the FIRST sector, too!
478
partitions[0].firstSector[0] = UINT8_C(0);
479
partitions[0].firstSector[1] = UINT8_C(1);
480
partitions[0].firstSector[2] = UINT8_C(0);
481
partitions[0].lastSector[0] = UINT8_C(255);
482
partitions[0].lastSector[1] = UINT8_C(255);
483
partitions[0].lastSector[2] = UINT8_C(255);
485
partitions[0].partitionType = UINT8_C(0xEE);
486
partitions[0].firstLBA = UINT32_C(1);
487
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
488
partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1);
489
} else { // disk is too big to represent, so fake it...
490
partitions[0].lengthLBA = UINT32_MAX;
494
} // MBRData::MakeProtectiveMBR()
496
// Create a partition of the specified number, starting LBA, and
497
// length. This function does *NO* error checking, so it's possible
498
// to seriously screw up a partition table using this function!
499
// Note: This function should NOT be used to create the 0xEE partition
500
// in a conventional GPT configuration, since that partition has
501
// specific size requirements that this function won't handle. It may
502
// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
503
// since those toss the rulebook away anyhow....
504
void MBRData::MakePart(int num, uint32_t start, uint32_t length, int type,
506
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
507
partitions[num].status = (uint8_t) bootable * (uint8_t) 0x80;
508
partitions[num].firstSector[0] = UINT8_C(0);
509
partitions[num].firstSector[1] = UINT8_C(0);
510
partitions[num].firstSector[2] = UINT8_C(0);
511
partitions[num].partitionType = (uint8_t) type;
512
partitions[num].lastSector[0] = UINT8_C(0);
513
partitions[num].lastSector[1] = UINT8_C(0);
514
partitions[num].lastSector[2] = UINT8_C(0);
515
partitions[num].firstLBA = start;
516
partitions[num].lengthLBA = length;
517
// If this is a "real" partition, set its CHS geometry
519
LBAtoCHS((uint64_t) start, partitions[num].firstSector);
520
LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector);
522
} // if valid partition number
523
} // MBRData::MakePart()
525
// Create a partition that fills the most available space. Returns
526
// 1 if partition was created, 0 otherwise. Intended for use in
527
// creating hybrid MBRs.
528
int MBRData::MakeBiggestPart(int i, int type) {
529
uint32_t start = UINT32_C(1); // starting point for each search
530
uint32_t firstBlock; // first block in a segment
531
uint32_t lastBlock; // last block in a segment
532
uint32_t segmentSize; // size of segment in blocks
533
uint32_t selectedSegment = UINT32_C(0); // location of largest segment
534
uint32_t selectedSize = UINT32_C(0); // size of largest segment in blocks
538
firstBlock = FindFirstAvailable(start);
539
if (firstBlock != UINT32_C(0)) { // something's free...
540
lastBlock = FindLastInFree(firstBlock);
541
segmentSize = lastBlock - firstBlock + UINT32_C(1);
542
if (segmentSize > selectedSize) {
543
selectedSize = segmentSize;
544
selectedSegment = firstBlock;
546
start = lastBlock + 1;
548
} while (firstBlock != 0);
549
if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
551
MakePart(i, selectedSegment, selectedSize, type, 0);
556
} // MBRData::MakeBiggestPart(int i)
558
// Delete partition #i
559
void MBRData::DeletePartition(int i) {
562
partitions[i].firstLBA = UINT32_C(0);
563
partitions[i].lengthLBA = UINT32_C(0);
564
partitions[i].status = UINT8_C(0);
565
partitions[i].partitionType = UINT8_C(0);
566
for (j = 0; j < 3; j++) {
567
partitions[i].firstSector[j] = UINT8_C(0);
568
partitions[i].lastSector[j] = UINT8_C(0);
569
} // for j (CHS data blanking)
570
} // MBRData::DeletePartition()
572
// Delete a partition if one exists at the specified location.
573
// Returns 1 if a partition was deleted, 0 otherwise....
574
// Used to help keep GPT & hybrid MBR partitions in sync....
575
int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
576
uint32_t start32, length32;
579
if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
580
start32 = (uint32_t) start64;
581
length32 = (uint32_t) length64;
582
for (i = 0; i < MAX_MBR_PARTS; i++) {
583
if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA = length32) &&
584
(partitions[i].partitionType != 0xEE)) {
589
} // if (match found)
590
} // for i (partition scan)
591
} // if (hybrid & GPT partition < 2TiB)
593
} // MBRData::DeleteByLocation()
595
// Optimizes the size of the 0xEE (EFI GPT) partition
596
void MBRData::OptimizeEESize(void) {
600
for (i = 0; i < 4; i++) {
601
// Check for non-empty and non-0xEE partitions
602
if ((partitions[i].partitionType != 0xEE) && (partitions[i].partitionType != 0x00))
604
if (partitions[i].partitionType == 0xEE) {
605
// Blank space before this partition; fill it....
606
if (IsFree(partitions[i].firstLBA - 1)) {
607
partitions[i].firstLBA = FindFirstInFree(partitions[i].firstLBA - 1);
609
// Blank space after this partition; fill it....
610
after = partitions[i].firstLBA + partitions[i].lengthLBA;
612
partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
613
} // if free space after
614
} // if partition is 0xEE
615
} // for partition loop
616
if (typeFlag == 0) { // No non-hybrid partitions found
617
MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
619
} // MBRData::OptimizeEESize()
621
/****************************************
623
* Functions to find data on free space *
625
****************************************/
627
// Finds the first free space on the disk from start onward; returns 0
628
// if none available....
629
uint32_t MBRData::FindFirstAvailable(uint32_t start) {
636
// ...now search through all partitions; if first is within an
637
// existing partition, move it to the next sector after that
638
// partition and repeat. If first was moved, set firstMoved
639
// flag; repeat until firstMoved is not set, so as to catch
640
// cases where partitions are out of sequential order....
643
for (i = 0; i < 4; i++) {
644
// Check if it's in the existing partition
645
if ((first >= partitions[i].firstLBA) &&
646
(first < (partitions[i].firstLBA + partitions[i].lengthLBA))) {
647
first = partitions[i].firstLBA + partitions[i].lengthLBA;
651
} while (firstMoved == 1);
652
if (first >= diskSize)
655
} // MBRData::FindFirstAvailable()
657
// Finds the last free sector on the disk from start forward.
658
uint32_t MBRData::FindLastInFree(uint32_t start) {
659
uint32_t nearestStart;
662
if ((diskSize <= UINT32_MAX) && (diskSize > 0))
663
nearestStart = diskSize - 1;
665
nearestStart = UINT32_MAX - 1;
666
for (i = 0; i < 4; i++) {
667
if ((nearestStart > partitions[i].firstLBA) &&
668
(partitions[i].firstLBA > start)) {
669
nearestStart = partitions[i].firstLBA - 1;
672
return (nearestStart);
673
} // MBRData::FindLastInFree()
675
// Finds the first free sector on the disk from start backward.
676
uint32_t MBRData::FindFirstInFree(uint32_t start) {
677
uint32_t bestLastLBA, thisLastLBA;
681
for (i = 0; i < 4; i++) {
682
thisLastLBA = partitions[i].firstLBA + partitions[i].lengthLBA;
683
if (thisLastLBA > 0) thisLastLBA--;
684
if ((thisLastLBA > bestLastLBA) && (thisLastLBA < start)) {
685
bestLastLBA = thisLastLBA + 1;
688
return (bestLastLBA);
689
} // MBRData::FindFirstInFree()
691
// Returns 1 if the specified sector is unallocated, 0 if it's
693
int MBRData::IsFree(uint32_t sector) {
695
uint32_t first, last;
697
for (i = 0; i < 4; i++) {
698
first = partitions[i].firstLBA;
699
// Note: Weird two-line thing to avoid subtracting 1 from a 0 value
700
// for an unsigned int....
701
last = first + partitions[i].lengthLBA;
702
if (last > 0) last--;
703
if ((first <= sector) && (last >= sector))
707
} // MBRData::IsFree()
709
/******************************************************
711
* Functions that extract data on specific partitions *
713
******************************************************/
715
uint8_t MBRData::GetStatus(int i) {
719
thePart = GetPartition(i);
721
retval = thePart->status;
725
} // MBRData::GetStatus()
727
uint8_t MBRData::GetType(int i) {
731
thePart = GetPartition(i);
733
retval = thePart->partitionType;
737
} // MBRData::GetType()
739
uint32_t MBRData::GetFirstSector(int i) {
743
thePart = GetPartition(i);
744
if (thePart != NULL) {
745
retval = thePart->firstLBA;
747
retval = UINT32_C(0);
749
} // MBRData::GetFirstSector()
751
uint32_t MBRData::GetLength(int i) {
755
thePart = GetPartition(i);
756
if (thePart != NULL) {
757
retval = thePart->lengthLBA;
759
retval = UINT32_C(0);
761
} // MBRData::GetLength()
763
// Return the MBR data as a GPT partition....
764
GPTPart MBRData::AsGPT(int i) {
768
uint64_t firstSector, lastSector;
769
char tempStr[NAME_SIZE];
771
newPart.BlankPartition();
772
origPart = GetPartition(i);
773
if (origPart != NULL) {
774
origType = origPart->partitionType;
776
// don't convert extended, hybrid protective, or null (non-existent)
777
// partitions (Note similar protection is in GPTData::XFormPartitions(),
778
// but I want it here too in case I call this function in another
779
// context in the future....)
780
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
781
(origType != 0x00) && (origType != 0xEE)) {
782
firstSector = (uint64_t) origPart->firstLBA;
783
newPart.SetFirstLBA(firstSector);
784
lastSector = firstSector + (uint64_t) origPart->lengthLBA;
785
if (lastSector > 0) lastSector--;
786
newPart.SetLastLBA(lastSector);
787
newPart.SetType(((uint16_t) origType) * 0x0100);
788
newPart.SetUniqueGUID(1);
789
newPart.SetAttributes(0);
790
newPart.SetName((unsigned char*) newPart.GetNameType(tempStr));
791
} // if not extended, protective, or non-existent
792
} // if (origPart != NULL)
794
} // MBRData::AsGPT()
796
/***********************
798
* Protected functions *
800
***********************/
802
// Return a pointer to a primary or logical partition, or NULL if
803
// the partition is out of range....
804
struct MBRRecord* MBRData::GetPartition(int i) {
805
MBRRecord* thePart = NULL;
807
if ((i >= 0) && (i < MAX_MBR_PARTS))
808
thePart = &partitions[i];