2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Ingo Weinhold, bonefish@cs.tu-berlin.de
11 # include <KernelExport.h>
21 #include "PartitionMap.h"
22 #include "PartitionMapParser.h"
25 //#define TRACE_ENABLED
28 # define TRACE(x) printf x
30 # define TRACE(x) dprintf x
37 # define ERROR(x) printf x
39 # define ERROR(x) dprintf x
44 // Maximal number of logical partitions per extended partition we allow.
45 static const int32 kMaxLogicalPartitionCount
= 128;
47 // Constants used to verify if a disk uses a GPT
48 static const int32 kGPTSignatureSize
= 8;
49 static const char kGPTSignature
[8] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
53 PartitionMapParser::PartitionMapParser(int deviceFD
, off_t sessionOffset
,
54 off_t sessionSize
, uint32 blockSize
)
57 fBlockSize(blockSize
),
58 fSessionOffset(sessionOffset
),
59 fSessionSize(sessionSize
),
60 fPartitionTable(NULL
),
67 PartitionMapParser::~PartitionMapParser()
74 PartitionMapParser::Parse(const uint8
* block
, PartitionMap
* map
)
80 bool hadToReFitSize
= false;
86 const partition_table
* table
= (const partition_table
*)block
;
87 error
= _ParsePrimary(table
, hadToReFitSize
);
89 partition_table table
;
90 error
= _ReadPartitionTable(0, &table
);
92 error
= _ParsePrimary(&table
, hadToReFitSize
);
94 if (fBlockSize
!= 512 && (hadToReFitSize
95 || !fMap
->Check(fSessionSize
))) {
96 // This might be a fixed 512 byte MBR on a non-512 medium.
97 // We do that for the anyboot images for example. so retry
98 // with a fixed 512 block size and see if we get better
100 int32 previousPartitionCount
= fMap
->CountNonEmptyPartitions();
101 uint32 previousBlockSize
= fBlockSize
;
102 TRACE(("intel: Parse(): trying with a fixed 512 block size\n"));
106 error
= _ParsePrimary(&table
, hadToReFitSize
);
108 if (fMap
->CountNonEmptyPartitions() < previousPartitionCount
109 || error
!= B_OK
|| hadToReFitSize
110 || !fMap
->Check(fSessionSize
)) {
111 // That didn't improve anything, let's revert.
112 TRACE(("intel: Parse(): try failed, reverting\n"));
113 fBlockSize
= previousBlockSize
;
115 error
= _ParsePrimary(&table
, hadToReFitSize
);
121 if (error
== B_OK
&& !fMap
->Check(fSessionSize
))
132 PartitionMapParser::_ParsePrimary(const partition_table
* table
,
133 bool& hadToReFitSize
)
138 // check the signature
139 if (table
->signature
!= kPartitionTableSectorSignature
) {
140 TRACE(("intel: _ParsePrimary(): invalid PartitionTable signature: %lx\n",
141 (uint32
)table
->signature
));
145 hadToReFitSize
= false;
148 for (int32 i
= 0; i
< 4; i
++) {
149 const partition_descriptor
* descriptor
= &table
->table
[i
];
150 PrimaryPartition
* partition
= fMap
->PrimaryPartitionAt(i
);
151 partition
->SetTo(descriptor
, 0, fBlockSize
);
153 // work-around potential BIOS/OS problems
154 hadToReFitSize
|= partition
->FitSizeToSession(fSessionSize
);
156 // ignore, if location is bad
157 if (!partition
->CheckLocation(fSessionSize
)) {
158 TRACE(("intel: _ParsePrimary(): partition %ld: bad location, "
164 // allocate a partition_table buffer
165 fPartitionTable
= new(nothrow
) partition_table
;
166 if (fPartitionTable
== NULL
)
169 // parse extended partitions
170 status_t error
= B_OK
;
171 for (int32 i
= 0; error
== B_OK
&& i
< 4; i
++) {
172 PrimaryPartition
* primary
= fMap
->PrimaryPartitionAt(i
);
173 if (primary
->IsExtended())
174 error
= _ParseExtended(primary
, primary
->Offset());
178 delete fPartitionTable
;
179 fPartitionTable
= NULL
;
187 PartitionMapParser::_ParseExtended(PrimaryPartition
* primary
, off_t offset
)
189 status_t error
= B_OK
;
190 int32 partitionCount
= 0;
191 while (error
== B_OK
) {
193 if (++partitionCount
> kMaxLogicalPartitionCount
) {
194 TRACE(("intel: _ParseExtended(): Maximal number of logical "
195 "partitions for extended partition reached. Cycle?\n"));
199 // read the partition table
201 error
= _ReadPartitionTable(offset
);
203 // check the signature
205 && fPartitionTable
->signature
!= kPartitionTableSectorSignature
) {
206 TRACE(("intel: _ParseExtended(): invalid partition table signature: "
207 "%lx\n", (uint32
)fPartitionTable
->signature
));
211 // ignore the partition table, if any error occured till now
213 TRACE(("intel: _ParseExtended(): ignoring this partition table\n"));
218 // Examine the table, there is exactly one extended and one
219 // non-extended logical partition. All four table entries are
220 // examined though. If there is no inner extended partition,
221 // the end of the linked list is reached.
222 // The first partition table describing both an "inner extended" parition
223 // and a "data" partition (non extended and not empty) is the start
224 // sector of the primary extended partition. The next partition table in
225 // the linked list is the start sector of the inner extended partition
226 // described in this partition table.
227 LogicalPartition extended
;
228 LogicalPartition nonExtended
;
229 for (int32 i
= 0; error
== B_OK
&& i
< 4; i
++) {
230 const partition_descriptor
* descriptor
= &fPartitionTable
->table
[i
];
231 if (descriptor
->is_empty())
234 LogicalPartition
* partition
= NULL
;
235 if (descriptor
->is_extended()) {
236 if (extended
.IsEmpty()) {
237 extended
.SetTo(descriptor
, offset
, primary
);
238 partition
= &extended
;
240 // only one extended partition allowed
242 TRACE(("intel: _ParseExtended(): "
243 "only one extended partition allowed\n"));
246 if (nonExtended
.IsEmpty()) {
247 nonExtended
.SetTo(descriptor
, offset
, primary
);
248 partition
= &nonExtended
;
250 // only one non-extended partition allowed
252 TRACE(("intel: _ParseExtended(): only one "
253 "non-extended partition allowed\n"));
256 if (partition
== NULL
)
259 // work-around potential BIOS/OS problems
260 partition
->FitSizeToSession(fSessionSize
);
262 // check the partition's location
263 if (!partition
->CheckLocation(fSessionSize
)) {
265 TRACE(("intel: _ParseExtended(): Invalid partition "
266 "location: pts: %lld, offset: %lld, size: %lld\n",
267 partition
->PartitionTableOffset(), partition
->Offset(),
272 // add non-extended partition to list
273 if (error
== B_OK
&& !nonExtended
.IsEmpty()) {
274 LogicalPartition
* partition
275 = new(nothrow
) LogicalPartition(nonExtended
);
277 primary
->AddLogicalPartition(partition
);
282 // prepare to parse next extended/non-extended partition pair
283 if (error
== B_OK
&& !extended
.IsEmpty())
284 offset
= extended
.Offset();
293 // _ReadPartitionTable
295 PartitionMapParser::_ReadPartitionTable(off_t offset
, partition_table
* table
)
297 int32 toRead
= sizeof(partition_table
);
300 if (offset
< 0 || offset
+ toRead
> fSessionSize
) {
301 TRACE(("intel: _ReadPartitionTable(): bad offset: %Ld\n", offset
));
306 table
= fPartitionTable
;
308 // Read the partition table from the device into the table structure
309 ssize_t bytesRead
= read_pos(fDeviceFD
, fSessionOffset
+ offset
,
311 if (bytesRead
!= (ssize_t
)toRead
) {
312 TRACE(("intel: _ReadPartitionTable(): reading the partition "
313 "table failed: %lx\n", errno
));
314 return bytesRead
< 0 ? errno
: B_IO_ERROR
;
317 // check for GPT signature "EFI PART"
318 // located in the 8bytes following the mbr
319 toRead
= kGPTSignatureSize
;
320 char gptSignature
[8];
321 bytesRead
= read_pos(fDeviceFD
, fSessionOffset
+ offset
322 + sizeof(partition_table
), &gptSignature
, toRead
);
323 if (bytesRead
!= (ssize_t
)toRead
) {
324 TRACE(("intel: _ReadPartitionTable(): checking for GPT "
325 "signature failed: %lx\n", errno
));
326 return bytesRead
< 0 ? errno
: B_IO_ERROR
;
328 if (memcmp(gptSignature
, kGPTSignature
, kGPTSignatureSize
) == 0) {
329 ERROR(("intel: Found GPT signature, ignoring.\n"));