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