xref: /haiku/src/add-ons/kernel/partitioning_systems/common/PartitionMapWriter.cpp (revision da8162be21b36442f34a731873d2358a0d63c25a)
1*61790bdbSJérôme Duval /*
2*61790bdbSJérôme Duval  * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
3*61790bdbSJérôme Duval  * Distributed under the terms of the MIT License.
4*61790bdbSJérôme Duval  *
5*61790bdbSJérôme Duval  * Authors:
6*61790bdbSJérôme Duval  *		Bryce Groff, brycegroff@gmail.com
7*61790bdbSJérôme Duval  */
8*61790bdbSJérôme Duval 
9*61790bdbSJérôme Duval #include "PartitionMapWriter.h"
10*61790bdbSJérôme Duval 
11*61790bdbSJérôme Duval #include <errno.h>
12*61790bdbSJérôme Duval #include <stdio.h>
13*61790bdbSJérôme Duval #include <string.h>
14*61790bdbSJérôme Duval #include <unistd.h>
15*61790bdbSJérôme Duval 
16*61790bdbSJérôme Duval #include <new>
17*61790bdbSJérôme Duval 
18*61790bdbSJérôme Duval #ifndef _USER_MODE
19*61790bdbSJérôme Duval #include <debug.h>
20*61790bdbSJérôme Duval #endif
21*61790bdbSJérôme Duval 
22*61790bdbSJérôme Duval #ifndef _USER_MODE
23*61790bdbSJérôme Duval #	include <KernelExport.h>
24*61790bdbSJérôme Duval #endif
25*61790bdbSJérôme Duval 
26*61790bdbSJérôme Duval #include "PartitionMap.h"
27*61790bdbSJérôme Duval 
28*61790bdbSJérôme Duval using std::nothrow;
29*61790bdbSJérôme Duval 
30*61790bdbSJérôme Duval 
31*61790bdbSJérôme Duval #define TRACE_ENABLED
32*61790bdbSJérôme Duval #ifdef TRACE_ENABLED
33*61790bdbSJérôme Duval #	ifdef _USER_MODE
34*61790bdbSJérôme Duval #		define TRACE(x) printf x
35*61790bdbSJérôme Duval #	else
36*61790bdbSJérôme Duval #		define TRACE(x) dprintf x
37*61790bdbSJérôme Duval #	endif
38*61790bdbSJérôme Duval #endif
39*61790bdbSJérôme Duval 
40*61790bdbSJérôme Duval 
41*61790bdbSJérôme Duval #if defined(__i386__) || defined(__x86_64__)
42*61790bdbSJérôme Duval #	ifndef _USER_MODE
43*61790bdbSJérôme Duval #		define MBR_HEADER "MBR.h"
44*61790bdbSJérôme Duval #		include MBR_HEADER
45*61790bdbSJérôme Duval #	endif
46*61790bdbSJérôme Duval #endif
47*61790bdbSJérôme Duval 
48*61790bdbSJérôme Duval 
49*61790bdbSJérôme Duval bool
check_logical_location(const LogicalPartition * child,const PrimaryPartition * parent)50*61790bdbSJérôme Duval check_logical_location(const LogicalPartition* child,
51*61790bdbSJérôme Duval 	const PrimaryPartition* parent)
52*61790bdbSJérôme Duval {
53*61790bdbSJérôme Duval 	if (child->PartitionTableOffset() % child->BlockSize() != 0) {
54*61790bdbSJérôme Duval 		TRACE(("check_logical_location() - PartitionTableOffset: %" B_PRId64 " "
55*61790bdbSJérôme Duval 			"not a multiple of media's block size: %" B_PRId32 "\n",
56*61790bdbSJérôme Duval 			child->PartitionTableOffset(), child->BlockSize()));
57*61790bdbSJérôme Duval 		return false;
58*61790bdbSJérôme Duval 	}
59*61790bdbSJérôme Duval 	if (child->Offset() % child->BlockSize() != 0) {
60*61790bdbSJérôme Duval 		TRACE(("check_logical_location() - Parition offset: %" B_PRId64 " "
61*61790bdbSJérôme Duval 			"is not a multiple of block size: %" B_PRId32 "\n", child->Offset(),
62*61790bdbSJérôme Duval 			child->BlockSize()));
63*61790bdbSJérôme Duval 		return false;
64*61790bdbSJérôme Duval 	}
65*61790bdbSJérôme Duval 	if (child->Size() % child->BlockSize() != 0) {
66*61790bdbSJérôme Duval 		TRACE(("check_logical_location() - Size: (%" B_PRId64 ") is not a "
67*61790bdbSJérôme Duval 			"multiple of block size: (%" B_PRId32 ")\n", child->Size(),
68*61790bdbSJérôme Duval 			child->BlockSize()));
69*61790bdbSJérôme Duval 		return false;
70*61790bdbSJérôme Duval 	}
71*61790bdbSJérôme Duval 	if (child->PartitionTableOffset() < parent->Offset()
72*61790bdbSJérôme Duval 		|| child->PartitionTableOffset() >= parent->Offset()
73*61790bdbSJérôme Duval 		+ parent->Size()) {
74*61790bdbSJérôme Duval 		TRACE(("check_logical_location() - Partition table: (%" B_PRId64 ") not"
75*61790bdbSJérôme Duval 			" within extended partition (start: %" B_PRId64 "), (end: "
76*61790bdbSJérôme Duval 			"%" B_PRId64 ")\n", child->PartitionTableOffset(), parent->Offset(),
77*61790bdbSJérôme Duval 			parent->Offset() + parent->Size()));
78*61790bdbSJérôme Duval 		return false;
79*61790bdbSJérôme Duval 	}
80*61790bdbSJérôme Duval 	if (child->Offset() + child->Size() > parent->Offset() + parent->Size()) {
81*61790bdbSJérôme Duval 		TRACE(("check_logical_location() - logical paritition does not lie "
82*61790bdbSJérôme Duval 			"within extended partition\n"));
83*61790bdbSJérôme Duval 		return false;
84*61790bdbSJérôme Duval 	}
85*61790bdbSJérôme Duval 	return true;
86*61790bdbSJérôme Duval }
87*61790bdbSJérôme Duval 
88*61790bdbSJérôme Duval 
PartitionMapWriter(int deviceFD,uint32 blockSize)89*61790bdbSJérôme Duval PartitionMapWriter::PartitionMapWriter(int deviceFD, uint32 blockSize)
90*61790bdbSJérôme Duval 	:
91*61790bdbSJérôme Duval 	fDeviceFD(deviceFD),
92*61790bdbSJérôme Duval 	fBlockSize(blockSize)
93*61790bdbSJérôme Duval {
94*61790bdbSJérôme Duval }
95*61790bdbSJérôme Duval 
96*61790bdbSJérôme Duval 
~PartitionMapWriter()97*61790bdbSJérôme Duval PartitionMapWriter::~PartitionMapWriter()
98*61790bdbSJérôme Duval {
99*61790bdbSJérôme Duval }
100*61790bdbSJérôme Duval 
101*61790bdbSJérôme Duval 
102*61790bdbSJérôme Duval status_t
WriteMBR(const PartitionMap * map,bool writeBootCode)103*61790bdbSJérôme Duval PartitionMapWriter::WriteMBR(const PartitionMap* map, bool writeBootCode)
104*61790bdbSJérôme Duval {
105*61790bdbSJérôme Duval 	if (map == NULL)
106*61790bdbSJérôme Duval 		return B_BAD_VALUE;
107*61790bdbSJérôme Duval 
108*61790bdbSJérôme Duval 	partition_table partitionTable;
109*61790bdbSJérôme Duval 	status_t error = _ReadBlock(0, partitionTable);
110*61790bdbSJérôme Duval 	if (error != B_OK)
111*61790bdbSJérôme Duval 		return error;
112*61790bdbSJérôme Duval #ifdef MBR_HEADER
113*61790bdbSJérôme Duval 	if (writeBootCode) {
114*61790bdbSJérôme Duval 		// the boot code must be small enough to fit in the code area
115*61790bdbSJérôme Duval 		STATIC_ASSERT(kMBRSize <= sizeof(partitionTable.code_area));
116*61790bdbSJérôme Duval 		partitionTable.clear_code_area();
117*61790bdbSJérôme Duval 		partitionTable.fill_code_area(kMBR, kMBRSize);
118*61790bdbSJérôme Duval 	}
119*61790bdbSJérôme Duval #endif
120*61790bdbSJérôme Duval 
121*61790bdbSJérôme Duval 	partitionTable.signature = kPartitionTableSectorSignature;
122*61790bdbSJérôme Duval 
123*61790bdbSJérôme Duval 	for (int i = 0; i < 4; i++) {
124*61790bdbSJérôme Duval 		partition_descriptor* descriptor = &partitionTable.table[i];
125*61790bdbSJérôme Duval 		const PrimaryPartition* partition = map->PrimaryPartitionAt(i);
126*61790bdbSJérôme Duval 
127*61790bdbSJérôme Duval 		partition->GetPartitionDescriptor(descriptor);
128*61790bdbSJérôme Duval 	}
129*61790bdbSJérôme Duval 
130*61790bdbSJérôme Duval 	error = _WriteBlock(0, partitionTable);
131*61790bdbSJérôme Duval 	return error;
132*61790bdbSJérôme Duval }
133*61790bdbSJérôme Duval 
134*61790bdbSJérôme Duval 
135*61790bdbSJérôme Duval status_t
WriteLogical(const LogicalPartition * logical,const PrimaryPartition * primary,bool clearCode)136*61790bdbSJérôme Duval PartitionMapWriter::WriteLogical(const LogicalPartition* logical,
137*61790bdbSJérôme Duval 	const PrimaryPartition* primary, bool clearCode)
138*61790bdbSJérôme Duval {
139*61790bdbSJérôme Duval 	if (logical == NULL || primary == NULL)
140*61790bdbSJérôme Duval 		return B_BAD_VALUE;
141*61790bdbSJérôme Duval 
142*61790bdbSJérôme Duval 	if (!check_logical_location(logical, primary))
143*61790bdbSJérôme Duval 		return B_BAD_DATA;
144*61790bdbSJérôme Duval 
145*61790bdbSJérôme Duval 	partition_table partitionTable;
146*61790bdbSJérôme Duval 	if (clearCode) {
147*61790bdbSJérôme Duval 		partitionTable.clear_code_area();
148*61790bdbSJérôme Duval 	} else {
149*61790bdbSJérôme Duval 		status_t error = _ReadBlock(logical->PartitionTableOffset(),
150*61790bdbSJérôme Duval 			partitionTable);
151*61790bdbSJérôme Duval 		if (error != B_OK)
152*61790bdbSJérôme Duval 			return error;
153*61790bdbSJérôme Duval 	}
154*61790bdbSJérôme Duval 
155*61790bdbSJérôme Duval 	partitionTable.signature = kPartitionTableSectorSignature;
156*61790bdbSJérôme Duval 
157*61790bdbSJérôme Duval 	partition_descriptor* descriptor = &partitionTable.table[0];
158*61790bdbSJérôme Duval 	logical->GetPartitionDescriptor(descriptor);
159*61790bdbSJérôme Duval 
160*61790bdbSJérôme Duval 	descriptor = &partitionTable.table[1];
161*61790bdbSJérôme Duval 	if (logical->Next() != NULL)
162*61790bdbSJérôme Duval 		logical->Next()->GetPartitionDescriptor(descriptor, true);
163*61790bdbSJérôme Duval 	else
164*61790bdbSJérôme Duval 		memset(descriptor, 0, sizeof(partition_descriptor));
165*61790bdbSJérôme Duval 
166*61790bdbSJérôme Duval 	// last two descriptors are empty
167*61790bdbSJérôme Duval 	for (int32 i = 2; i < 4; i++) {
168*61790bdbSJérôme Duval 		descriptor = &partitionTable.table[i];
169*61790bdbSJérôme Duval 		memset(descriptor, 0, sizeof(partition_descriptor));
170*61790bdbSJérôme Duval 	}
171*61790bdbSJérôme Duval 
172*61790bdbSJérôme Duval 	status_t error = _WriteBlock(logical->PartitionTableOffset(),
173*61790bdbSJérôme Duval 		partitionTable);
174*61790bdbSJérôme Duval 	return error;
175*61790bdbSJérôme Duval }
176*61790bdbSJérôme Duval 
177*61790bdbSJérôme Duval 
178*61790bdbSJérôme Duval status_t
WriteExtendedHead(const LogicalPartition * logical,const PrimaryPartition * primary,bool clearCode)179*61790bdbSJérôme Duval PartitionMapWriter::WriteExtendedHead(const LogicalPartition* logical,
180*61790bdbSJérôme Duval 	const PrimaryPartition* primary, bool clearCode)
181*61790bdbSJérôme Duval {
182*61790bdbSJérôme Duval 	if (primary == NULL)
183*61790bdbSJérôme Duval 		return B_BAD_VALUE;
184*61790bdbSJérôme Duval 
185*61790bdbSJérôme Duval 	partition_table partitionTable;
186*61790bdbSJérôme Duval 	if (clearCode) {
187*61790bdbSJérôme Duval 		partitionTable.clear_code_area();
188*61790bdbSJérôme Duval 	} else {
189*61790bdbSJérôme Duval 		status_t error = _ReadBlock(primary->Offset(), partitionTable);
190*61790bdbSJérôme Duval 		if (error != B_OK)
191*61790bdbSJérôme Duval 			return error;
192*61790bdbSJérôme Duval 	}
193*61790bdbSJérôme Duval 
194*61790bdbSJérôme Duval 	partitionTable.signature = kPartitionTableSectorSignature;
195*61790bdbSJérôme Duval 	partition_descriptor* descriptor;
196*61790bdbSJérôme Duval 	if (logical == NULL) {
197*61790bdbSJérôme Duval 		for (int32 i = 0; i < 4; i++) {
198*61790bdbSJérôme Duval 			descriptor = &partitionTable.table[i];
199*61790bdbSJérôme Duval 			memset(descriptor, 0, sizeof(partition_descriptor));
200*61790bdbSJérôme Duval 		}
201*61790bdbSJérôme Duval 	} else {
202*61790bdbSJérôme Duval 		LogicalPartition partition;
203*61790bdbSJérôme Duval 		partition.SetPartitionTableOffset(primary->Offset());
204*61790bdbSJérôme Duval 		partition.SetBlockSize(logical->BlockSize());
205*61790bdbSJérôme Duval 		partition.SetOffset(logical->Offset());
206*61790bdbSJérôme Duval 		partition.SetSize(logical->Size());
207*61790bdbSJérôme Duval 		partition.SetType(logical->Type());
208*61790bdbSJérôme Duval 
209*61790bdbSJérôme Duval 		// set the logicals partition table to the correct location
210*61790bdbSJérôme Duval 		descriptor = &partitionTable.table[0];
211*61790bdbSJérôme Duval 		partition.GetPartitionDescriptor(descriptor);
212*61790bdbSJérôme Duval 
213*61790bdbSJérôme Duval 		descriptor = &partitionTable.table[1];
214*61790bdbSJérôme Duval 		LogicalPartition* next = logical->Next();
215*61790bdbSJérôme Duval 		if (next != NULL)
216*61790bdbSJérôme Duval 			next->GetPartitionDescriptor(descriptor, true);
217*61790bdbSJérôme Duval 		else
218*61790bdbSJérôme Duval 			memset(descriptor, 0, sizeof(partition_descriptor));
219*61790bdbSJérôme Duval 
220*61790bdbSJérôme Duval 		// last two descriptors are empty
221*61790bdbSJérôme Duval 		for (int32 i = 2; i < 4; i++) {
222*61790bdbSJérôme Duval 			descriptor = &partitionTable.table[i];
223*61790bdbSJérôme Duval 			memset(descriptor, 0, sizeof(partition_descriptor));
224*61790bdbSJérôme Duval 		}
225*61790bdbSJérôme Duval 	}
226*61790bdbSJérôme Duval 
227*61790bdbSJérôme Duval 	status_t error = _WriteBlock(primary->Offset(), partitionTable);
228*61790bdbSJérôme Duval 	if (error != B_OK)
229*61790bdbSJérôme Duval 		return error;
230*61790bdbSJérôme Duval 
231*61790bdbSJérôme Duval 	return B_OK;
232*61790bdbSJérôme Duval }
233*61790bdbSJérôme Duval 
234*61790bdbSJérôme Duval 
235*61790bdbSJérôme Duval 
236*61790bdbSJérôme Duval status_t
ClearExtendedHead(const PrimaryPartition * primary)237*61790bdbSJérôme Duval PartitionMapWriter::ClearExtendedHead(const PrimaryPartition* primary)
238*61790bdbSJérôme Duval {
239*61790bdbSJérôme Duval 	if (primary == NULL)
240*61790bdbSJérôme Duval 		return B_BAD_VALUE;
241*61790bdbSJérôme Duval 
242*61790bdbSJérôme Duval 	partition_table partitionTable;
243*61790bdbSJérôme Duval 	partitionTable.clear_code_area();
244*61790bdbSJérôme Duval 	partitionTable.signature = kPartitionTableSectorSignature;
245*61790bdbSJérôme Duval 
246*61790bdbSJérôme Duval 	partition_descriptor* descriptor;
247*61790bdbSJérôme Duval 	for (int32 i = 0; i < 4; i++) {
248*61790bdbSJérôme Duval 		descriptor = &partitionTable.table[i];
249*61790bdbSJérôme Duval 		memset(descriptor, 0, sizeof(partition_descriptor));
250*61790bdbSJérôme Duval 	}
251*61790bdbSJérôme Duval 
252*61790bdbSJérôme Duval 	status_t error = _WriteBlock(primary->Offset(), partitionTable);
253*61790bdbSJérôme Duval 	if (error != B_OK)
254*61790bdbSJérôme Duval 		return error;
255*61790bdbSJérôme Duval 
256*61790bdbSJérôme Duval 	return B_OK;
257*61790bdbSJérôme Duval }
258*61790bdbSJérôme Duval 
259*61790bdbSJérôme Duval 
260*61790bdbSJérôme Duval status_t
_ReadBlock(off_t partitionOffset,partition_table & partitionTable)261*61790bdbSJérôme Duval PartitionMapWriter::_ReadBlock(off_t partitionOffset,
262*61790bdbSJérôme Duval 	partition_table& partitionTable)
263*61790bdbSJérôme Duval {
264*61790bdbSJérôme Duval 	if (partitionOffset < 0)
265*61790bdbSJérôme Duval 		return B_BAD_VALUE;
266*61790bdbSJérôme Duval 	// TODO: If fBlockSize > sizeof(partition_table) then stop/read NULL after
267*61790bdbSJérôme Duval 	if (read_pos(fDeviceFD, partitionOffset, &partitionTable,
268*61790bdbSJérôme Duval 		sizeof(partitionTable)) != sizeof(partitionTable)) {
269*61790bdbSJérôme Duval 		status_t error = errno;
270*61790bdbSJérôme Duval 		if (error == B_OK)
271*61790bdbSJérôme Duval 			error = B_IO_ERROR;
272*61790bdbSJérôme Duval 
273*61790bdbSJérôme Duval 		return error;
274*61790bdbSJérôme Duval 	}
275*61790bdbSJérôme Duval 
276*61790bdbSJérôme Duval 	return B_OK;
277*61790bdbSJérôme Duval }
278*61790bdbSJérôme Duval 
279*61790bdbSJérôme Duval 
280*61790bdbSJérôme Duval status_t
_WriteBlock(off_t partitionOffset,const partition_table & partitionTable)281*61790bdbSJérôme Duval PartitionMapWriter::_WriteBlock(off_t partitionOffset,
282*61790bdbSJérôme Duval 	const partition_table& partitionTable)
283*61790bdbSJérôme Duval {
284*61790bdbSJérôme Duval 	if (partitionOffset < 0)
285*61790bdbSJérôme Duval 		return B_BAD_VALUE;
286*61790bdbSJérôme Duval 	// TODO: maybe clear the rest of the block if
287*61790bdbSJérôme Duval 	// fBlockSize > sizeof(partition_table)?
288*61790bdbSJérôme Duval 	if (write_pos(fDeviceFD, partitionOffset, &partitionTable,
289*61790bdbSJérôme Duval 		sizeof(partitionTable)) != sizeof(partitionTable)) {
290*61790bdbSJérôme Duval 		status_t error = errno;
291*61790bdbSJérôme Duval 		if (error == B_OK)
292*61790bdbSJérôme Duval 			error = B_IO_ERROR;
293*61790bdbSJérôme Duval 
294*61790bdbSJérôme Duval 		return error;
295*61790bdbSJérôme Duval 	}
296*61790bdbSJérôme Duval 
297*61790bdbSJérôme Duval 	return B_OK;
298*61790bdbSJérôme Duval }
299*61790bdbSJérôme Duval 
300