vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / partitioning_systems / intel / PartitionMapWriter.cpp
blob88824cf460044721ef6fe3beb20bf1cf6ed2c131
1 /*
2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Bryce Groff, brycegroff@gmail.com
7 */
9 #include "PartitionMapWriter.h"
11 #include <errno.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
16 #include <new>
18 #ifndef _USER_MODE
19 #include <debug.h>
20 #endif
22 #ifndef _USER_MODE
23 # include <KernelExport.h>
24 #endif
26 #include "PartitionMap.h"
28 using std::nothrow;
31 #define TRACE_ENABLED
32 #ifdef TRACE_ENABLED
33 # ifdef _USER_MODE
34 # define TRACE(x) printf x
35 # else
36 # define TRACE(x) dprintf x
37 # endif
38 #endif
41 #if defined(__INTEL__) || defined(__x86_64__)
42 # ifndef _USER_MODE
43 # define MBR_HEADER "MBR.h"
44 # include MBR_HEADER
45 # endif
46 #endif
49 bool
50 check_logical_location(const LogicalPartition* child,
51 const PrimaryPartition* parent)
53 if (child->PartitionTableOffset() % child->BlockSize() != 0) {
54 TRACE(("check_logical_location() - PartitionTableOffset: %" B_PRId64 " "
55 "not a multiple of media's block size: %" B_PRId32 "\n",
56 child->PartitionTableOffset(), child->BlockSize()));
57 return false;
59 if (child->Offset() % child->BlockSize() != 0) {
60 TRACE(("check_logical_location() - Parition offset: %" B_PRId64 " "
61 "is not a multiple of block size: %" B_PRId32 "\n", child->Offset(),
62 child->BlockSize()));
63 return false;
65 if (child->Size() % child->BlockSize() != 0) {
66 TRACE(("check_logical_location() - Size: (%" B_PRId64 ") is not a "
67 "multiple of block size: (%" B_PRId32 ")\n", child->Size(),
68 child->BlockSize()));
69 return false;
71 if (child->PartitionTableOffset() < parent->Offset()
72 || child->PartitionTableOffset() >= parent->Offset()
73 + parent->Size()) {
74 TRACE(("check_logical_location() - Partition table: (%" B_PRId64 ") not"
75 " within extended partition (start: %" B_PRId64 "), (end: "
76 "%" B_PRId64 ")\n", child->PartitionTableOffset(), parent->Offset(),
77 parent->Offset() + parent->Size()));
78 return false;
80 if (child->Offset() + child->Size() > parent->Offset() + parent->Size()) {
81 TRACE(("check_logical_location() - logical paritition does not lie "
82 "within extended partition\n"));
83 return false;
85 return true;
89 PartitionMapWriter::PartitionMapWriter(int deviceFD, uint32 blockSize)
91 fDeviceFD(deviceFD),
92 fBlockSize(blockSize)
97 PartitionMapWriter::~PartitionMapWriter()
102 status_t
103 PartitionMapWriter::WriteMBR(const PartitionMap* map, bool writeBootCode)
105 if (map == NULL)
106 return B_BAD_VALUE;
108 partition_table partitionTable;
109 status_t error = _ReadBlock(0, partitionTable);
110 if (error != B_OK)
111 return error;
112 #ifdef MBR_HEADER
113 if (writeBootCode) {
114 // the boot code must be small enough to fit in the code area
115 STATIC_ASSERT(kMBRSize <= sizeof(partitionTable.code_area));
116 partitionTable.clear_code_area();
117 partitionTable.fill_code_area(kMBR, kMBRSize);
119 #endif
121 partitionTable.signature = kPartitionTableSectorSignature;
123 for (int i = 0; i < 4; i++) {
124 partition_descriptor* descriptor = &partitionTable.table[i];
125 const PrimaryPartition* partition = map->PrimaryPartitionAt(i);
127 partition->GetPartitionDescriptor(descriptor);
130 error = _WriteBlock(0, partitionTable);
131 return error;
135 status_t
136 PartitionMapWriter::WriteLogical(const LogicalPartition* logical,
137 const PrimaryPartition* primary, bool clearCode)
139 if (logical == NULL || primary == NULL)
140 return B_BAD_VALUE;
142 if (!check_logical_location(logical, primary))
143 return B_BAD_DATA;
145 partition_table partitionTable;
146 if (clearCode) {
147 partitionTable.clear_code_area();
148 } else {
149 status_t error = _ReadBlock(logical->PartitionTableOffset(),
150 partitionTable);
151 if (error != B_OK)
152 return error;
155 partitionTable.signature = kPartitionTableSectorSignature;
157 partition_descriptor* descriptor = &partitionTable.table[0];
158 logical->GetPartitionDescriptor(descriptor);
160 descriptor = &partitionTable.table[1];
161 if (logical->Next() != NULL)
162 logical->Next()->GetPartitionDescriptor(descriptor, true);
163 else
164 memset(descriptor, 0, sizeof(partition_descriptor));
166 // last two descriptors are empty
167 for (int32 i = 2; i < 4; i++) {
168 descriptor = &partitionTable.table[i];
169 memset(descriptor, 0, sizeof(partition_descriptor));
172 status_t error = _WriteBlock(logical->PartitionTableOffset(),
173 partitionTable);
174 return error;
178 status_t
179 PartitionMapWriter::WriteExtendedHead(const LogicalPartition* logical,
180 const PrimaryPartition* primary, bool clearCode)
182 if (primary == NULL)
183 return B_BAD_VALUE;
185 partition_table partitionTable;
186 if (clearCode) {
187 partitionTable.clear_code_area();
188 } else {
189 status_t error = _ReadBlock(primary->Offset(), partitionTable);
190 if (error != B_OK)
191 return error;
194 partitionTable.signature = kPartitionTableSectorSignature;
195 partition_descriptor* descriptor;
196 if (logical == NULL) {
197 for (int32 i = 0; i < 4; i++) {
198 descriptor = &partitionTable.table[i];
199 memset(descriptor, 0, sizeof(partition_descriptor));
201 } else {
202 LogicalPartition partition;
203 partition.SetPartitionTableOffset(primary->Offset());
204 partition.SetBlockSize(logical->BlockSize());
205 partition.SetOffset(logical->Offset());
206 partition.SetSize(logical->Size());
207 partition.SetType(logical->Type());
209 // set the logicals partition table to the correct location
210 descriptor = &partitionTable.table[0];
211 partition.GetPartitionDescriptor(descriptor);
213 descriptor = &partitionTable.table[1];
214 LogicalPartition* next = logical->Next();
215 if (next != NULL)
216 next->GetPartitionDescriptor(descriptor, true);
217 else
218 memset(descriptor, 0, sizeof(partition_descriptor));
220 // last two descriptors are empty
221 for (int32 i = 2; i < 4; i++) {
222 descriptor = &partitionTable.table[i];
223 memset(descriptor, 0, sizeof(partition_descriptor));
227 status_t error = _WriteBlock(primary->Offset(), partitionTable);
228 if (error != B_OK)
229 return error;
231 return B_OK;
236 status_t
237 PartitionMapWriter::ClearExtendedHead(const PrimaryPartition* primary)
239 if (primary == NULL)
240 return B_BAD_VALUE;
242 partition_table partitionTable;
243 partitionTable.clear_code_area();
244 partitionTable.signature = kPartitionTableSectorSignature;
246 partition_descriptor* descriptor;
247 for (int32 i = 0; i < 4; i++) {
248 descriptor = &partitionTable.table[i];
249 memset(descriptor, 0, sizeof(partition_descriptor));
252 status_t error = _WriteBlock(primary->Offset(), partitionTable);
253 if (error != B_OK)
254 return error;
256 return B_OK;
260 status_t
261 PartitionMapWriter::_ReadBlock(off_t partitionOffset,
262 partition_table& partitionTable)
264 if (partitionOffset < 0)
265 return B_BAD_VALUE;
266 // TODO: If fBlockSize > sizeof(partition_table) then stop/read NULL after
267 if (read_pos(fDeviceFD, partitionOffset, &partitionTable,
268 sizeof(partitionTable)) != sizeof(partitionTable)) {
269 status_t error = errno;
270 if (error == B_OK)
271 error = B_IO_ERROR;
273 return error;
276 return B_OK;
280 status_t
281 PartitionMapWriter::_WriteBlock(off_t partitionOffset,
282 const partition_table& partitionTable)
284 if (partitionOffset < 0)
285 return B_BAD_VALUE;
286 // TODO: maybe clear the rest of the block if
287 // fBlockSize > sizeof(partition_table)?
288 if (write_pos(fDeviceFD, partitionOffset, &partitionTable,
289 sizeof(partitionTable)) != sizeof(partitionTable)) {
290 status_t error = errno;
291 if (error == B_OK)
292 error = B_IO_ERROR;
294 return error;
297 return B_OK;