1 /*
2 * Copyright 2007, Ingo Weinhold, bonefish@users.sf.net.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7 #include "ExtendedPartitionAddOn.h"
8
9 #include <new>
10 #include <stdio.h>
11
12 #include <DiskDeviceTypes.h>
13 #include <MutablePartition.h>
14 #include <PartitioningInfo.h>
15
16 #include <AutoDeleter.h>
17
18 #include "IntelDiskSystem.h"
19
20
21 //#define TRACE_EXTENDED_PARTITION_ADD_ON
22 #undef TRACE
23 #ifdef TRACE_EXTENDED_PARTITION_ADD_ON
24 # define TRACE(x...) printf(x)
25 #else
26 # define TRACE(x...) do {} while (false)
27 #endif
28
29 #define PTS_OFFSET (63 * Partition()->BlockSize())
30
31
32 using std::nothrow;
33
34
35 static const uint32 kDiskSystemFlags =
36 0
37 // | B_DISK_SYSTEM_SUPPORTS_CHECKING
38 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING
39 // | B_DISK_SYSTEM_SUPPORTS_RESIZING
40 // | B_DISK_SYSTEM_SUPPORTS_MOVING
41 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
42 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
43 // | B_DISK_SYSTEM_SUPPORTS_INITIALIZING
44 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
45
46 // | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD
47 // | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD
48 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME
49 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE
50 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS
51 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD
52 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD
53 // | B_DISK_SYSTEM_SUPPORTS_NAME
54 ;
55
56
57 // #pragma mark - ExtendedPartitionAddOn
58
59
ExtendedPartitionAddOn()60 ExtendedPartitionAddOn::ExtendedPartitionAddOn()
61 :
62 BDiskSystemAddOn(kPartitionTypeIntelExtended, kDiskSystemFlags)
63 {
64 }
65
66
~ExtendedPartitionAddOn()67 ExtendedPartitionAddOn::~ExtendedPartitionAddOn()
68 {
69 }
70
71
72 status_t
CreatePartitionHandle(BMutablePartition * partition,BPartitionHandle ** _handle)73 ExtendedPartitionAddOn::CreatePartitionHandle(BMutablePartition* partition,
74 BPartitionHandle** _handle)
75 {
76 ExtendedPartitionHandle* handle
77 = new(nothrow) ExtendedPartitionHandle(partition);
78 if (!handle)
79 return B_NO_MEMORY;
80
81 status_t error = handle->Init();
82 if (error != B_OK) {
83 delete handle;
84 return error;
85 }
86
87 *_handle = handle;
88 return B_OK;
89 }
90
91
92 bool
CanInitialize(const BMutablePartition * partition)93 ExtendedPartitionAddOn::CanInitialize(const BMutablePartition* partition)
94 {
95 // If it's big enough, we can initialize it.
96 return false;
97 }
98
99
100 status_t
ValidateInitialize(const BMutablePartition * partition,BString * name,const char * parameters)101 ExtendedPartitionAddOn::ValidateInitialize(const BMutablePartition* partition,
102 BString* name, const char* parameters)
103 {
104 if (!CanInitialize(partition)
105 || (parameters != NULL && parameters[0] != '\0')) {
106 return B_BAD_VALUE;
107 }
108
109 // we don't support a content name
110 if (name != NULL)
111 name->Truncate(0);
112
113 return B_OK;
114 }
115
116
117 status_t
Initialize(BMutablePartition * partition,const char * name,const char * parameters,BPartitionHandle ** _handle)118 ExtendedPartitionAddOn::Initialize(BMutablePartition* partition,
119 const char* name, const char* parameters, BPartitionHandle** _handle)
120 {
121 if (!CanInitialize(partition)
122 || (name != NULL && name[0] != '\0')
123 || (parameters != NULL && parameters[0] != '\0')) {
124 return B_BAD_VALUE;
125 }
126
127 // create the handle
128 ExtendedPartitionHandle* handle
129 = new(nothrow) ExtendedPartitionHandle(partition);
130 if (!handle)
131 return B_NO_MEMORY;
132 ObjectDeleter<ExtendedPartitionHandle> handleDeleter(handle);
133
134 // init the partition
135 status_t error = partition->SetContentType(Name());
136 if (error != B_OK)
137 return error;
138 // TODO: The content type could as well be set by the caller.
139
140 partition->SetContentName(NULL);
141 partition->SetContentParameters(NULL);
142 partition->SetContentSize(
143 sector_align(partition->Size(), partition->BlockSize()));
144 partition->Changed(B_PARTITION_CHANGED_INITIALIZATION);
145
146 *_handle = handleDeleter.Detach();
147
148 return B_OK;
149 }
150
151
152 // #pragma mark - ExtendedPartitionHandle
153
154
ExtendedPartitionHandle(BMutablePartition * partition)155 ExtendedPartitionHandle::ExtendedPartitionHandle(BMutablePartition* partition)
156 :
157 BPartitionHandle(partition)
158 {
159 }
160
161
~ExtendedPartitionHandle()162 ExtendedPartitionHandle::~ExtendedPartitionHandle()
163 {
164 }
165
166
167 status_t
Init()168 ExtendedPartitionHandle::Init()
169 {
170 // initialize the extended partition from the mutable partition
171
172 BMutablePartition* partition = Partition();
173
174 // our parent has already set the child cookie to the primary partition.
175 fPrimaryPartition = (PrimaryPartition*)partition->ChildCookie();
176 if (!fPrimaryPartition)
177 return B_BAD_VALUE;
178
179 if (!fPrimaryPartition->IsExtended())
180 return B_BAD_VALUE;
181
182 // init the child partitions
183 int32 count = partition->CountChildren();
184 for (int32 i = 0; i < count; i++) {
185 BMutablePartition* child = partition->ChildAt(i);
186
187 PartitionType type;
188 if (!type.SetType(child->Type()))
189 return B_BAD_VALUE;
190
191 void* handle = parse_driver_settings_string(child->Parameters());
192 if (handle == NULL)
193 return B_ERROR;
194
195 bool active = get_driver_boolean_parameter(
196 handle, "active", false, true);
197
198 off_t ptsOffset = 0;
199 const char* buffer = get_driver_parameter(handle,
200 "partition_table_offset", NULL, NULL);
201 if (buffer != NULL)
202 ptsOffset = strtoull(buffer, NULL, 10);
203 else {
204 unload_driver_settings(handle);
205 return B_BAD_VALUE;
206 }
207 unload_driver_settings(handle);
208
209 LogicalPartition* logical = new(nothrow) LogicalPartition;
210 if (!logical)
211 return B_NO_MEMORY;
212
213 logical->SetTo(child->Offset(), child->Size(), type.Type(), active,
214 ptsOffset, fPrimaryPartition);
215
216 child->SetChildCookie(logical);
217 }
218
219 return B_OK;
220 }
221
222
223 uint32
SupportedOperations(uint32 mask)224 ExtendedPartitionHandle::SupportedOperations(uint32 mask)
225 {
226 uint32 flags = 0;
227
228 // creating child
229 if ((mask & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) != 0) {
230 BPartitioningInfo info;
231 if (GetPartitioningInfo(&info) == B_OK
232 && info.CountPartitionableSpaces() > 1) {
233 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD;
234 }
235 }
236
237 return flags;
238 }
239
240
241 uint32
SupportedChildOperations(const BMutablePartition * child,uint32 mask)242 ExtendedPartitionHandle::SupportedChildOperations(
243 const BMutablePartition* child, uint32 mask)
244 {
245 return B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD;
246 }
247
248
249 status_t
GetNextSupportedType(const BMutablePartition * child,int32 * cookie,BString * type)250 ExtendedPartitionHandle::GetNextSupportedType(const BMutablePartition* child,
251 int32* cookie, BString* type)
252 {
253 int32 index = *cookie;
254 const partition_type* nextType;
255 PartitionMap partitionMap;
256 while (true) {
257 nextType = partitionMap.GetNextSupportedPartitionType(index);
258 if (nextType == NULL)
259 return B_ENTRY_NOT_FOUND;
260 index++;
261 if (nextType->used
262 && strcmp(nextType->name, kPartitionTypeIntelExtended) != 0)
263 break;
264 }
265
266 if (!nextType)
267 return B_ENTRY_NOT_FOUND;
268
269 type->SetTo(nextType->name);
270 *cookie = index;
271
272 return B_OK;
273 }
274
275
276 status_t
GetPartitioningInfo(BPartitioningInfo * info)277 ExtendedPartitionHandle::GetPartitioningInfo(BPartitioningInfo* info)
278 {
279 // init to the full size (minus the first PTS_OFFSET)
280 BMutablePartition* partition = Partition();
281 off_t offset = partition->Offset() + PTS_OFFSET;
282 off_t size = partition->Size() - PTS_OFFSET;
283 status_t error = info->SetTo(offset, size);
284 if (error != B_OK)
285 return error;
286
287 // exclude the space of the existing logical partitions
288 int32 count = partition->CountChildren();
289 for (int32 i = 0; i < count; i++) {
290 BMutablePartition* child = partition->ChildAt(i);
291 error = info->ExcludeOccupiedSpace(child->Offset(),
292 child->Size() + PTS_OFFSET + Partition()->BlockSize());
293 if (error != B_OK)
294 return error;
295
296 LogicalPartition* logical = (LogicalPartition*)child->ChildCookie();
297 if (logical == NULL)
298 return B_BAD_VALUE;
299 error = info->ExcludeOccupiedSpace(
300 logical->PartitionTableOffset(),
301 PTS_OFFSET + Partition()->BlockSize());
302 if (error != B_OK)
303 return error;
304 }
305
306 return B_OK;
307 }
308
309
310 status_t
GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,BPartitionParameterEditor ** editor)311 ExtendedPartitionHandle::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,
312 BPartitionParameterEditor** editor)
313 {
314 *editor = NULL;
315 return B_NOT_SUPPORTED;
316 }
317
318
319 status_t
ValidateCreateChild(off_t * _offset,off_t * _size,const char * typeString,BString * name,const char * parameters)320 ExtendedPartitionHandle::ValidateCreateChild(off_t* _offset, off_t* _size,
321 const char* typeString, BString* name, const char* parameters)
322 {
323 // check type
324 if (!typeString)
325 return B_BAD_VALUE;
326
327 // check name
328 if (name)
329 name->Truncate(0);
330
331 // check the free space situation
332 BPartitioningInfo info;
333 status_t error = GetPartitioningInfo(&info);
334 if (error != B_OK)
335 return error;
336
337 // any space in the partition at all?
338 int32 spacesCount = info.CountPartitionableSpaces();
339 if (spacesCount == 0)
340 return B_BAD_VALUE;
341
342 // check offset and size
343 off_t offset = sector_align(*_offset, Partition()->BlockSize());
344 off_t size = sector_align(*_size, Partition()->BlockSize());
345 // TODO: Rather round size up?
346 off_t end = offset + size;
347
348 // get the first partitionable space the requested interval intersects with
349 int32 spaceIndex = -1;
350 int32 closestSpaceIndex = -1;
351 off_t closestSpaceDistance = 0;
352 for (int32 i = 0; i < spacesCount; i++) {
353 off_t spaceOffset, spaceSize;
354 info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize);
355 off_t spaceEnd = spaceOffset + spaceSize;
356
357 if ((spaceOffset >= offset && spaceOffset < end)
358 || (offset >= spaceOffset && offset < spaceEnd)) {
359 spaceIndex = i;
360 break;
361 }
362
363 off_t distance;
364 if (offset < spaceOffset)
365 distance = spaceOffset - end;
366 else
367 distance = spaceEnd - offset;
368
369 if (closestSpaceIndex == -1 || distance < closestSpaceDistance) {
370 closestSpaceIndex = i;
371 closestSpaceDistance = distance;
372 }
373 }
374
375 // get the space we found
376 off_t spaceOffset, spaceSize;
377 info.GetPartitionableSpaceAt(
378 spaceIndex >= 0 ? spaceIndex : closestSpaceIndex, &spaceOffset,
379 &spaceSize);
380 off_t spaceEnd = spaceOffset + spaceSize;
381
382 // If the requested intervald doesn't intersect with any space yet, move
383 // it, so that it does.
384 if (spaceIndex < 0) {
385 spaceIndex = closestSpaceIndex;
386 if (offset < spaceOffset) {
387 offset = spaceOffset;
388 end = offset + size;
389 } else {
390 end = spaceEnd;
391 offset = end - size;
392 }
393 }
394
395 // move/shrink the interval, so that it fully lies within the space
396 if (offset < spaceOffset) {
397 offset = spaceOffset;
398 end = offset + size;
399 if (end > spaceEnd) {
400 end = spaceEnd;
401 size = end - offset;
402 }
403 } else if (end > spaceEnd) {
404 end = spaceEnd;
405 offset = end - size;
406 if (offset < spaceOffset) {
407 offset = spaceOffset;
408 size = end - offset;
409 }
410 }
411
412 *_offset = offset;
413 *_size = size;
414
415 return B_OK;
416 }
417
418
419 status_t
CreateChild(off_t offset,off_t size,const char * typeString,const char * name,const char * _parameters,BMutablePartition ** _child)420 ExtendedPartitionHandle::CreateChild(off_t offset, off_t size,
421 const char* typeString, const char* name, const char* _parameters,
422 BMutablePartition** _child)
423 {
424 // check type
425 PartitionType type;
426 if (!type.SetType(typeString) || type.IsEmpty())
427 return B_BAD_VALUE;
428
429 // check name
430 if (name != NULL && name[0] != '\0')
431 return B_BAD_VALUE;
432
433 // offset properly aligned?
434 if (offset != sector_align(offset, Partition()->BlockSize())
435 || size != sector_align(size, Partition()->BlockSize()))
436 return B_BAD_VALUE;
437
438 // check the free space situation
439 BPartitioningInfo info;
440 status_t error = GetPartitioningInfo(&info);
441 if (error != B_OK)
442 return error;
443
444 bool foundSpace = false;
445 off_t end = offset + size;
446 int32 spacesCount = info.CountPartitionableSpaces();
447 for (int32 i = 0; i < spacesCount; i++) {
448 off_t spaceOffset, spaceSize;
449 info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize);
450 off_t spaceEnd = spaceOffset + spaceSize;
451
452 if (offset >= spaceOffset && end <= spaceEnd) {
453 foundSpace = true;
454 break;
455 }
456 }
457
458 if (!foundSpace)
459 return B_BAD_VALUE;
460
461 BString parameters(_parameters);
462 parameters << "partition_table_offset " << offset - PTS_OFFSET << " ;\n";
463 // everything looks good, create the child
464 BMutablePartition* child;
465 error = Partition()->CreateChild(-1, typeString,
466 NULL, parameters.String(), &child);
467 if (error != B_OK)
468 return error;
469
470 // init the child
471 child->SetOffset(offset);
472 child->SetSize(size);
473 child->SetBlockSize(Partition()->BlockSize());
474 //child->SetFlags(0);
475 child->SetChildCookie(Partition());
476
477 *_child = child;
478 return B_OK;
479 }
480
481
482 status_t
DeleteChild(BMutablePartition * child)483 ExtendedPartitionHandle::DeleteChild(BMutablePartition* child)
484 {
485 BMutablePartition* parent = child->Parent();
486 status_t error = parent->DeleteChild(child);
487
488 return error;
489 }
490