2 * Copyright 2007, Ingo Weinhold, bonefish@users.sf.net.
3 * Distributed under the terms of the MIT License.
7 #include "ExtendedPartitionAddOn.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
23 #ifdef TRACE_EXTENDED_PARTITION_ADD_ON
24 # define TRACE(x...) printf(x)
26 # define TRACE(x...) do {} while (false)
29 #define PTS_OFFSET (63 * Partition()->BlockSize())
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()
73 ExtendedPartitionAddOn::CreatePartitionHandle(BMutablePartition
* partition
,
74 BPartitionHandle
** _handle
)
76 ExtendedPartitionHandle
* handle
77 = new(nothrow
) ExtendedPartitionHandle(partition
);
81 status_t error
= handle
->Init();
93 ExtendedPartitionAddOn::CanInitialize(const BMutablePartition
* partition
)
95 // If it's big enough, we can initialize it.
101 ExtendedPartitionAddOn::ValidateInitialize(const BMutablePartition
* partition
,
102 BString
* name
, const char* parameters
)
104 if (!CanInitialize(partition
)
105 || (parameters
!= NULL
&& parameters
[0] != '\0')) {
109 // we don't support a content name
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')) {
128 ExtendedPartitionHandle
* handle
129 = new(nothrow
) ExtendedPartitionHandle(partition
);
132 ObjectDeleter
<ExtendedPartitionHandle
> handleDeleter(handle
);
134 // init the partition
135 status_t error
= partition
->SetContentType(Name());
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();
151 // #pragma mark - ExtendedPartitionHandle
154 ExtendedPartitionHandle::ExtendedPartitionHandle(BMutablePartition
* partition
)
156 BPartitionHandle(partition
)
161 ExtendedPartitionHandle::~ExtendedPartitionHandle()
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
)
178 if (!fPrimaryPartition
->IsExtended())
181 // init the child partitions
182 int32 count
= partition
->CountChildren();
183 for (int32 i
= 0; i
< count
; i
++) {
184 BMutablePartition
* child
= partition
->ChildAt(i
);
187 if (!type
.SetType(child
->Type()))
190 void* handle
= parse_driver_settings_string(child
->Parameters());
194 bool active
= get_driver_boolean_parameter(
195 handle
, "active", false, true);
198 const char* buffer
= get_driver_parameter(handle
,
199 "partition_table_offset", NULL
, NULL
);
201 ptsOffset
= strtoull(buffer
, NULL
, 10);
203 delete_driver_settings(handle
);
206 delete_driver_settings(handle
);
208 LogicalPartition
* logical
= new(nothrow
) LogicalPartition
;
212 logical
->SetTo(child
->Offset(), child
->Size(), type
.Type(), active
,
213 ptsOffset
, fPrimaryPartition
);
215 child
->SetChildCookie(logical
);
223 ExtendedPartitionHandle::SupportedOperations(uint32 mask
)
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
;
241 ExtendedPartitionHandle::SupportedChildOperations(
242 const BMutablePartition
* child
, uint32 mask
)
244 return B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD
;
249 ExtendedPartitionHandle::GetNextSupportedType(const BMutablePartition
* child
,
250 int32
* cookie
, BString
* type
)
252 int32 index
= *cookie
;
253 const partition_type
* nextType
;
254 PartitionMap partitionMap
;
256 nextType
= partitionMap
.GetNextSupportedPartitionType(index
);
257 if (nextType
== NULL
)
258 return B_ENTRY_NOT_FOUND
;
261 && strcmp(nextType
->name
, kPartitionTypeIntelExtended
) != 0)
266 return B_ENTRY_NOT_FOUND
;
268 type
->SetTo(nextType
->name
);
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
);
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());
295 LogicalPartition
* logical
= (LogicalPartition
*)child
->ChildCookie();
298 error
= info
->ExcludeOccupiedSpace(
299 logical
->PartitionTableOffset(),
300 PTS_OFFSET
+ Partition()->BlockSize());
310 ExtendedPartitionHandle::GetParameterEditor(B_PARAMETER_EDITOR_TYPE type
,
311 BPartitionParameterEditor
** editor
)
314 return B_NOT_SUPPORTED
;
319 ExtendedPartitionHandle::ValidateCreateChild(off_t
* _offset
, off_t
* _size
,
320 const char* typeString
, BString
* name
, const char* parameters
)
330 // check the free space situation
331 BPartitioningInfo info
;
332 status_t error
= GetPartitioningInfo(&info
);
336 // any space in the partition at all?
337 int32 spacesCount
= info
.CountPartitionableSpaces();
338 if (spacesCount
== 0)
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
)) {
363 if (offset
< spaceOffset
)
364 distance
= spaceOffset
- end
;
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
,
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
;
394 // move/shrink the interval, so that it fully lies within the space
395 if (offset
< spaceOffset
) {
396 offset
= spaceOffset
;
398 if (end
> spaceEnd
) {
402 } else if (end
> spaceEnd
) {
405 if (offset
< spaceOffset
) {
406 offset
= spaceOffset
;
419 ExtendedPartitionHandle::CreateChild(off_t offset
, off_t size
,
420 const char* typeString
, const char* name
, const char* _parameters
,
421 BMutablePartition
** _child
)
425 if (!type
.SetType(typeString
) || type
.IsEmpty())
429 if (name
!= NULL
&& name
[0] != '\0')
432 // offset properly aligned?
433 if (offset
!= sector_align(offset
, Partition()->BlockSize())
434 || size
!= sector_align(size
, Partition()->BlockSize()))
437 // check the free space situation
438 BPartitioningInfo info
;
439 status_t error
= GetPartitioningInfo(&info
);
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
) {
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
);
470 child
->SetOffset(offset
);
471 child
->SetSize(size
);
472 child
->SetBlockSize(Partition()->BlockSize());
473 //child->SetFlags(0);
474 child
->SetChildCookie(Partition());
482 ExtendedPartitionHandle::DeleteChild(BMutablePartition
* child
)
484 BMutablePartition
* parent
= child
->Parent();
485 status_t error
= parent
->DeleteChild(child
);