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