3rdparty/licenseReport: Add seperate LGPL checks
[haiku.git] / src / add-ons / disk_systems / intel / ExtendedPartitionAddOn.cpp
blob3145d8cc99fd1676dc9730d0e252bb459143cb39
1 /*
2 * Copyright 2007, Ingo Weinhold, bonefish@users.sf.net.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ExtendedPartitionAddOn.h"
9 #include <new>
10 #include <stdio.h>
12 #include <DiskDeviceTypes.h>
13 #include <MutablePartition.h>
14 #include <PartitioningInfo.h>
16 #include <AutoDeleter.h>
18 #include "IntelDiskSystem.h"
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
29 #define PTS_OFFSET (63 * Partition()->BlockSize())
32 using std::nothrow;
35 static const uint32 kDiskSystemFlags =
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
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
57 // #pragma mark - ExtendedPartitionAddOn
60 ExtendedPartitionAddOn::ExtendedPartitionAddOn()
62 BDiskSystemAddOn(kPartitionTypeIntelExtended, kDiskSystemFlags)
67 ExtendedPartitionAddOn::~ExtendedPartitionAddOn()
72 status_t
73 ExtendedPartitionAddOn::CreatePartitionHandle(BMutablePartition* partition,
74 BPartitionHandle** _handle)
76 ExtendedPartitionHandle* handle
77 = new(nothrow) ExtendedPartitionHandle(partition);
78 if (!handle)
79 return B_NO_MEMORY;
81 status_t error = handle->Init();
82 if (error != B_OK) {
83 delete handle;
84 return error;
87 *_handle = handle;
88 return B_OK;
92 bool
93 ExtendedPartitionAddOn::CanInitialize(const BMutablePartition* partition)
95 // If it's big enough, we can initialize it.
96 return false;
100 status_t
101 ExtendedPartitionAddOn::ValidateInitialize(const BMutablePartition* partition,
102 BString* name, const char* parameters)
104 if (!CanInitialize(partition)
105 || (parameters != NULL && parameters[0] != '\0')) {
106 return B_BAD_VALUE;
109 // we don't support a content name
110 if (name != NULL)
111 name->Truncate(0);
113 return B_OK;
117 status_t
118 ExtendedPartitionAddOn::Initialize(BMutablePartition* partition,
119 const char* name, const char* parameters, BPartitionHandle** _handle)
121 if (!CanInitialize(partition)
122 || (name != NULL && name[0] != '\0')
123 || (parameters != NULL && parameters[0] != '\0')) {
124 return B_BAD_VALUE;
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);
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.
140 partition->SetContentName(NULL);
141 partition->SetContentParameters(NULL);
142 partition->SetContentSize(
143 sector_align(partition->Size(), partition->BlockSize()));
145 *_handle = handleDeleter.Detach();
147 return B_OK;
151 // #pragma mark - ExtendedPartitionHandle
154 ExtendedPartitionHandle::ExtendedPartitionHandle(BMutablePartition* partition)
156 BPartitionHandle(partition)
161 ExtendedPartitionHandle::~ExtendedPartitionHandle()
166 status_t
167 ExtendedPartitionHandle::Init()
169 // initialize the extended partition from the mutable partition
171 BMutablePartition* partition = Partition();
173 // our parent has already set the child cookie to the primary partition.
174 fPrimaryPartition = (PrimaryPartition*)partition->ChildCookie();
175 if (!fPrimaryPartition)
176 return B_BAD_VALUE;
178 if (!fPrimaryPartition->IsExtended())
179 return B_BAD_VALUE;
181 // init the child partitions
182 int32 count = partition->CountChildren();
183 for (int32 i = 0; i < count; i++) {
184 BMutablePartition* child = partition->ChildAt(i);
186 PartitionType type;
187 if (!type.SetType(child->Type()))
188 return B_BAD_VALUE;
190 void* handle = parse_driver_settings_string(child->Parameters());
191 if (handle == NULL)
192 return B_ERROR;
194 bool active = get_driver_boolean_parameter(
195 handle, "active", false, true);
197 off_t ptsOffset = 0;
198 const char* buffer = get_driver_parameter(handle,
199 "partition_table_offset", NULL, NULL);
200 if (buffer != NULL)
201 ptsOffset = strtoull(buffer, NULL, 10);
202 else {
203 delete_driver_settings(handle);
204 return B_BAD_VALUE;
206 delete_driver_settings(handle);
208 LogicalPartition* logical = new(nothrow) LogicalPartition;
209 if (!logical)
210 return B_NO_MEMORY;
212 logical->SetTo(child->Offset(), child->Size(), type.Type(), active,
213 ptsOffset, fPrimaryPartition);
215 child->SetChildCookie(logical);
218 return B_OK;
222 uint32
223 ExtendedPartitionHandle::SupportedOperations(uint32 mask)
225 uint32 flags = 0;
227 // creating child
228 if ((mask & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) != 0) {
229 BPartitioningInfo info;
230 if (GetPartitioningInfo(&info) == B_OK
231 && info.CountPartitionableSpaces() > 1) {
232 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD;
236 return flags;
240 uint32
241 ExtendedPartitionHandle::SupportedChildOperations(
242 const BMutablePartition* child, uint32 mask)
244 return B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD;
248 status_t
249 ExtendedPartitionHandle::GetNextSupportedType(const BMutablePartition* child,
250 int32* cookie, BString* type)
252 int32 index = *cookie;
253 const partition_type* nextType;
254 PartitionMap partitionMap;
255 while (true) {
256 nextType = partitionMap.GetNextSupportedPartitionType(index);
257 if (nextType == NULL)
258 return B_ENTRY_NOT_FOUND;
259 index++;
260 if (nextType->used
261 && strcmp(nextType->name, kPartitionTypeIntelExtended) != 0)
262 break;
265 if (!nextType)
266 return B_ENTRY_NOT_FOUND;
268 type->SetTo(nextType->name);
269 *cookie = index;
271 return B_OK;
275 status_t
276 ExtendedPartitionHandle::GetPartitioningInfo(BPartitioningInfo* info)
278 // init to the full size (minus the first PTS_OFFSET)
279 BMutablePartition* partition = Partition();
280 off_t offset = partition->Offset() + PTS_OFFSET;
281 off_t size = partition->Size() - PTS_OFFSET;
282 status_t error = info->SetTo(offset, size);
283 if (error != B_OK)
284 return error;
286 // exclude the space of the existing logical partitions
287 int32 count = partition->CountChildren();
288 for (int32 i = 0; i < count; i++) {
289 BMutablePartition* child = partition->ChildAt(i);
290 error = info->ExcludeOccupiedSpace(child->Offset(),
291 child->Size() + PTS_OFFSET + Partition()->BlockSize());
292 if (error != B_OK)
293 return error;
295 LogicalPartition* logical = (LogicalPartition*)child->ChildCookie();
296 if (logical == NULL)
297 return B_BAD_VALUE;
298 error = info->ExcludeOccupiedSpace(
299 logical->PartitionTableOffset(),
300 PTS_OFFSET + Partition()->BlockSize());
301 if (error != B_OK)
302 return error;
305 return B_OK;
309 status_t
310 ExtendedPartitionHandle::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type,
311 BPartitionParameterEditor** editor)
313 *editor = NULL;
314 return B_NOT_SUPPORTED;
318 status_t
319 ExtendedPartitionHandle::ValidateCreateChild(off_t* _offset, off_t* _size,
320 const char* typeString, BString* name, const char* parameters)
322 // check type
323 if (!typeString)
324 return B_BAD_VALUE;
326 // check name
327 if (name)
328 name->Truncate(0);
330 // check the free space situation
331 BPartitioningInfo info;
332 status_t error = GetPartitioningInfo(&info);
333 if (error != B_OK)
334 return error;
336 // any space in the partition at all?
337 int32 spacesCount = info.CountPartitionableSpaces();
338 if (spacesCount == 0)
339 return B_BAD_VALUE;
341 // check offset and size
342 off_t offset = sector_align(*_offset, Partition()->BlockSize());
343 off_t size = sector_align(*_size, Partition()->BlockSize());
344 // TODO: Rather round size up?
345 off_t end = offset + size;
347 // get the first partitionable space the requested interval intersects with
348 int32 spaceIndex = -1;
349 int32 closestSpaceIndex = -1;
350 off_t closestSpaceDistance = 0;
351 for (int32 i = 0; i < spacesCount; i++) {
352 off_t spaceOffset, spaceSize;
353 info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize);
354 off_t spaceEnd = spaceOffset + spaceSize;
356 if ((spaceOffset >= offset && spaceOffset < end)
357 || (offset >= spaceOffset && offset < spaceEnd)) {
358 spaceIndex = i;
359 break;
362 off_t distance;
363 if (offset < spaceOffset)
364 distance = spaceOffset - end;
365 else
366 distance = spaceEnd - offset;
368 if (closestSpaceIndex == -1 || distance < closestSpaceDistance) {
369 closestSpaceIndex = i;
370 closestSpaceDistance = distance;
374 // get the space we found
375 off_t spaceOffset, spaceSize;
376 info.GetPartitionableSpaceAt(
377 spaceIndex >= 0 ? spaceIndex : closestSpaceIndex, &spaceOffset,
378 &spaceSize);
379 off_t spaceEnd = spaceOffset + spaceSize;
381 // If the requested intervald doesn't intersect with any space yet, move
382 // it, so that it does.
383 if (spaceIndex < 0) {
384 spaceIndex = closestSpaceIndex;
385 if (offset < spaceOffset) {
386 offset = spaceOffset;
387 end = offset + size;
388 } else {
389 end = spaceEnd;
390 offset = end - size;
394 // move/shrink the interval, so that it fully lies within the space
395 if (offset < spaceOffset) {
396 offset = spaceOffset;
397 end = offset + size;
398 if (end > spaceEnd) {
399 end = spaceEnd;
400 size = end - offset;
402 } else if (end > spaceEnd) {
403 end = spaceEnd;
404 offset = end - size;
405 if (offset < spaceOffset) {
406 offset = spaceOffset;
407 size = end - offset;
411 *_offset = offset;
412 *_size = size;
414 return B_OK;
418 status_t
419 ExtendedPartitionHandle::CreateChild(off_t offset, off_t size,
420 const char* typeString, const char* name, const char* _parameters,
421 BMutablePartition** _child)
423 // check type
424 PartitionType type;
425 if (!type.SetType(typeString) || type.IsEmpty())
426 return B_BAD_VALUE;
428 // check name
429 if (name != NULL && name[0] != '\0')
430 return B_BAD_VALUE;
432 // offset properly aligned?
433 if (offset != sector_align(offset, Partition()->BlockSize())
434 || size != sector_align(size, Partition()->BlockSize()))
435 return B_BAD_VALUE;
437 // check the free space situation
438 BPartitioningInfo info;
439 status_t error = GetPartitioningInfo(&info);
440 if (error != B_OK)
441 return error;
443 bool foundSpace = false;
444 off_t end = offset + size;
445 int32 spacesCount = info.CountPartitionableSpaces();
446 for (int32 i = 0; i < spacesCount; i++) {
447 off_t spaceOffset, spaceSize;
448 info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize);
449 off_t spaceEnd = spaceOffset + spaceSize;
451 if (offset >= spaceOffset && end <= spaceEnd) {
452 foundSpace = true;
453 break;
457 if (!foundSpace)
458 return B_BAD_VALUE;
460 BString parameters(_parameters);
461 parameters << "partition_table_offset " << offset - PTS_OFFSET << " ;\n";
462 // everything looks good, create the child
463 BMutablePartition* child;
464 error = Partition()->CreateChild(-1, typeString,
465 NULL, parameters.String(), &child);
466 if (error != B_OK)
467 return error;
469 // init the child
470 child->SetOffset(offset);
471 child->SetSize(size);
472 child->SetBlockSize(Partition()->BlockSize());
473 //child->SetFlags(0);
474 child->SetChildCookie(Partition());
476 *_child = child;
477 return B_OK;
481 status_t
482 ExtendedPartitionHandle::DeleteChild(BMutablePartition* child)
484 BMutablePartition* parent = child->Parent();
485 status_t error = parent->DeleteChild(child);
487 return error;