xref: /haiku/src/system/kernel/disk_device_manager/KPartitioningSystem.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 // KPartitioningSystem.cpp
2 
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 
7 #include <ddm_modules.h>
8 #include <KDiskDevice.h>
9 #include <KDiskDeviceJob.h>
10 #include <KDiskDeviceManager.h>
11 #include <KDiskDeviceUtils.h>
12 #include <KPartition.h>
13 #include <KPartitioningSystem.h>
14 
15 // constructor
16 KPartitioningSystem::KPartitioningSystem(const char *name)
17 	: KDiskSystem(name),
18 	  fModule(NULL)
19 {
20 }
21 
22 // destructor
23 KPartitioningSystem::~KPartitioningSystem()
24 {
25 }
26 
27 // Init
28 status_t
29 KPartitioningSystem::Init()
30 {
31 	status_t error = KDiskSystem::Init();
32 	if (error != B_OK)
33 		return error;
34 	error = Load();
35 	if (error != B_OK)
36 		return error;
37 	error = SetPrettyName(fModule->pretty_name);
38 	SetFlags(fModule->flags & ~(uint32)B_DISK_SYSTEM_IS_FILE_SYSTEM);
39 	Unload();
40 	return error;
41 }
42 
43 // Identify
44 float
45 KPartitioningSystem::Identify(KPartition *partition, void **cookie)
46 {
47 	if (!partition || !cookie || !fModule || !fModule->identify_partition)
48 		return -1;
49 	int fd = -1;
50 	if (partition->Open(O_RDONLY, &fd) != B_OK)
51 		return -1;
52 	float result = fModule->identify_partition(fd, partition->PartitionData(),
53 											   cookie);
54 	close(fd);
55 	return result;
56 }
57 
58 // Scan
59 status_t
60 KPartitioningSystem::Scan(KPartition *partition, void *cookie)
61 {
62 	if (!partition || !fModule || !fModule->scan_partition)
63 		return B_ERROR;
64 	int fd = -1;
65 	status_t result = partition->Open(O_RDONLY, &fd);
66 	if (result != B_OK)
67 		return result;
68 	result = fModule->scan_partition(fd, partition->PartitionData(), cookie);
69 	close(fd);
70 	return result;
71 }
72 
73 // FreeIdentifyCookie
74 void
75 KPartitioningSystem::FreeIdentifyCookie(KPartition *partition, void *cookie)
76 {
77 	if (!partition || !fModule || !fModule->free_identify_partition_cookie)
78 		return;
79 	fModule->free_identify_partition_cookie(partition->PartitionData(),
80 											cookie);
81 }
82 
83 // FreeCookie
84 void
85 KPartitioningSystem::FreeCookie(KPartition *partition)
86 {
87 	if (!partition || !fModule || !fModule->free_partition_cookie
88 		|| partition->ParentDiskSystem() != this) {
89 		return;
90 	}
91 	fModule->free_partition_cookie(partition->PartitionData());
92 	partition->SetCookie(NULL);
93 }
94 
95 // FreeContentCookie
96 void
97 KPartitioningSystem::FreeContentCookie(KPartition *partition)
98 {
99 	if (!partition || !fModule || !fModule->free_partition_content_cookie
100 		|| partition->DiskSystem() != this) {
101 		return;
102 	}
103 	fModule->free_partition_content_cookie(partition->PartitionData());
104 	partition->SetContentCookie(NULL);
105 }
106 
107 // SupportsRepairing
108 bool
109 KPartitioningSystem::SupportsRepairing(KPartition *partition, bool checkOnly,
110 									   bool *whileMounted)
111 {
112 	bool _whileMounted = false;
113 	if (!whileMounted)
114 		whileMounted = &_whileMounted;
115 	if (!partition || partition->DiskSystem() != this || !fModule
116 		|| !fModule->supports_repairing) {
117 		return (*whileMounted = false);
118 	}
119 	bool result = fModule->supports_repairing(partition->PartitionData(),
120 											  checkOnly);
121 	*whileMounted = result;
122 	return result;
123 }
124 
125 // SupportsResizing
126 bool
127 KPartitioningSystem::SupportsResizing(KPartition *partition,
128 									  bool *whileMounted)
129 {
130 	bool _whileMounted = false;
131 	if (!whileMounted)
132 		whileMounted = &_whileMounted;
133 	if (!partition || partition->DiskSystem() != this || !fModule ||
134 		!fModule->supports_resizing) {
135 		return (*whileMounted = false);
136 	}
137 	bool result = fModule->supports_resizing(partition->PartitionData());
138 	*whileMounted = result;
139 	return result;
140 }
141 
142 // SupportsResizingChild
143 bool
144 KPartitioningSystem::SupportsResizingChild(KPartition *child)
145 {
146 	return (child && child->Parent() && child->ParentDiskSystem() == this
147 			&& fModule && fModule->supports_resizing_child
148 			&& fModule->supports_resizing_child(
149 						child->Parent()->PartitionData(),
150 						child->PartitionData()));
151 }
152 
153 // SupportsMoving
154 bool
155 KPartitioningSystem::SupportsMoving(KPartition *partition, bool *isNoOp)
156 {
157 	bool _isNoOp = false;
158 	if (!isNoOp)
159 		isNoOp = &_isNoOp;
160 	if (!partition || partition->DiskSystem() != this || !fModule
161 		|| !fModule->supports_moving) {
162 		return (*isNoOp = false);
163 	}
164 	return fModule->supports_moving(partition->PartitionData(), isNoOp);
165 }
166 
167 // SupportsMovingChild
168 bool
169 KPartitioningSystem::SupportsMovingChild(KPartition *child)
170 {
171 	return (child && child->Parent() && child->ParentDiskSystem() != this
172 			&& fModule && fModule->supports_moving_child
173 			&& fModule->supports_moving_child(child->Parent()->PartitionData(),
174 											  child->PartitionData()));
175 }
176 
177 // SupportsSettingName
178 bool
179 KPartitioningSystem::SupportsSettingName(KPartition *partition)
180 {
181 	return (partition && partition->ParentDiskSystem() == this
182 			&& fModule && fModule->supports_setting_name
183 			&& fModule->supports_setting_name(partition->PartitionData()));
184 }
185 
186 // SupportsSettingContentName
187 bool
188 KPartitioningSystem::SupportsSettingContentName(KPartition *partition,
189 												bool *whileMounted)
190 {
191 	bool _whileMounted = false;
192 	if (!whileMounted)
193 		whileMounted = &_whileMounted;
194 	if (!partition || partition->DiskSystem() != this || !fModule
195 		|| !fModule->supports_setting_content_name) {
196 		return (*whileMounted = false);
197 	}
198 	bool result = fModule->supports_setting_content_name(
199 		partition->PartitionData());
200 	*whileMounted = result;
201 	return result;
202 }
203 
204 // SupportsSettingType
205 bool
206 KPartitioningSystem::SupportsSettingType(KPartition *partition)
207 {
208 	return (partition && partition->ParentDiskSystem() == this
209 			&& fModule && fModule->supports_setting_type
210 			&& fModule->supports_setting_type(partition->PartitionData()));
211 }
212 
213 // SupportsSettingParameters
214 bool
215 KPartitioningSystem::SupportsSettingParameters(KPartition *partition)
216 {
217 	return (partition && partition->ParentDiskSystem() == this
218 			&& fModule && fModule->supports_setting_parameters
219 			&& fModule->supports_setting_parameters(
220 					partition->PartitionData()));
221 }
222 
223 // SupportsSettingContentParameters
224 bool
225 KPartitioningSystem::SupportsSettingContentParameters(KPartition *partition,
226 													  bool *whileMounted)
227 {
228 	bool _whileMounted = false;
229 	if (!whileMounted)
230 		whileMounted = &_whileMounted;
231 	if (!partition || partition->DiskSystem() != this || !fModule
232 		|| !fModule->supports_setting_content_parameters) {
233 		return (*whileMounted = false);
234 	}
235 	bool result = fModule->supports_setting_content_parameters(
236 		partition->PartitionData());
237 	*whileMounted = result;
238 	return result;
239 }
240 
241 // SupportsInitializing
242 bool
243 KPartitioningSystem::SupportsInitializing(KPartition *partition)
244 {
245 	return (partition && fModule && fModule->supports_initializing
246 			&& fModule->supports_initializing(partition->PartitionData()));
247 }
248 
249 // SupportsInitializingChild
250 bool
251 KPartitioningSystem::SupportsInitializingChild(KPartition *child,
252 											   const char *diskSystem)
253 {
254 	return (child && child->ParentDiskSystem() == this && diskSystem
255 			&& fModule && fModule->supports_initializing_child
256 			&& fModule->supports_initializing_child(child->PartitionData(),
257 													diskSystem));
258 }
259 
260 // SupportsCreatingChild
261 bool
262 KPartitioningSystem::SupportsCreatingChild(KPartition *partition)
263 {
264 	return (partition && partition->DiskSystem() == this
265 			&& fModule && fModule->supports_creating_child
266 			&& fModule->supports_creating_child(partition->PartitionData()));
267 }
268 
269 // SupportsDeletingChild
270 bool
271 KPartitioningSystem::SupportsDeletingChild(KPartition *child)
272 {
273 	return (child && child->Parent() && child->ParentDiskSystem() == this
274 			&& fModule && fModule->supports_deleting_child
275 			&& fModule->supports_deleting_child(
276 					child->Parent()->PartitionData(), child->PartitionData()));
277 }
278 
279 // IsSubSystemFor
280 bool
281 KPartitioningSystem::IsSubSystemFor(KPartition *partition)
282 {
283 	return (partition && fModule && fModule->is_sub_system_for
284 			&& fModule->is_sub_system_for(partition->PartitionData()));
285 }
286 
287 // ValidateResize
288 bool
289 KPartitioningSystem::ValidateResize(KPartition *partition, off_t *size)
290 {
291 	return (partition && size && partition->DiskSystem() == this && fModule
292 			&& fModule->validate_resize
293 			&& fModule->validate_resize(partition->PartitionData(), size));
294 }
295 
296 // ValidateResizeChild
297 bool
298 KPartitioningSystem::ValidateResizeChild(KPartition *child, off_t *size)
299 {
300 	return (child && size && child->Parent()
301 			&& child->ParentDiskSystem() == this && fModule
302 			&& fModule->validate_resize_child
303 			&& fModule->validate_resize_child(child->Parent()->PartitionData(),
304 											  child->PartitionData(), size));
305 }
306 
307 // ValidateMove
308 bool
309 KPartitioningSystem::ValidateMove(KPartition *partition, off_t *start)
310 {
311 	return (partition && start && partition->DiskSystem() == this && fModule
312 			&& fModule->validate_move
313 			&& fModule->validate_move(partition->PartitionData(), start));
314 }
315 
316 // ValidateMoveChild
317 bool
318 KPartitioningSystem::ValidateMoveChild(KPartition *child, off_t *start)
319 {
320 	return (child && start && child->Parent()
321 			&& child->ParentDiskSystem() == this && fModule
322 			&& fModule->validate_move_child
323 			&& fModule->validate_move_child(child->Parent()->PartitionData(),
324 											child->PartitionData(), start));
325 }
326 
327 // ValidateSetName
328 bool
329 KPartitioningSystem::ValidateSetName(KPartition *partition, char *name)
330 {
331 	return (partition && name && partition->Parent()
332 			&& partition->ParentDiskSystem() == this && fModule
333 			&& fModule->validate_set_name
334 			&& fModule->validate_set_name(partition->PartitionData(), name));
335 }
336 
337 // ValidateSetContentName
338 bool
339 KPartitioningSystem::ValidateSetContentName(KPartition *partition, char *name)
340 {
341 	return (partition && name && partition->DiskSystem() == this
342 			&& fModule && fModule->validate_set_content_name
343 			&& fModule->validate_set_content_name(partition->PartitionData(),
344 												  name));
345 }
346 
347 // ValidateSetType
348 bool
349 KPartitioningSystem::ValidateSetType(KPartition *partition, const char *type)
350 {
351 	return (partition && type && partition->ParentDiskSystem() == this
352 			&& fModule && fModule->validate_set_type
353 			&& fModule->validate_set_type(partition->PartitionData(), type));
354 }
355 
356 // ValidateSetParameters
357 bool
358 KPartitioningSystem::ValidateSetParameters(KPartition *partition,
359 										   const char *parameters)
360 {
361 	return (partition && partition->ParentDiskSystem() == this
362 			&& fModule && fModule->validate_set_parameters
363 			&& fModule->validate_set_parameters(partition->PartitionData(),
364 					parameters));
365 }
366 
367 // ValidateSetContentParameters
368 bool
369 KPartitioningSystem::ValidateSetContentParameters(KPartition *partition,
370 												  const char *parameters)
371 {
372 	return (partition && partition->DiskSystem() == this && fModule
373 			&& fModule->validate_set_content_parameters
374 			&& fModule->validate_set_content_parameters(
375 					partition->PartitionData(), parameters));
376 }
377 
378 // ValidateInitialize
379 bool
380 KPartitioningSystem::ValidateInitialize(KPartition *partition, char *name,
381 										const char *parameters)
382 {
383 	return (partition && name && fModule && fModule->validate_initialize
384 			&& fModule->validate_initialize(partition->PartitionData(), name,
385 											parameters));
386 }
387 
388 // ValidateCreateChild
389 bool
390 KPartitioningSystem::ValidateCreateChild(KPartition *partition, off_t *start,
391 										 off_t *size, const char *type,
392 										 const char *parameters, int32 *index)
393 {
394 	int32 _index = 0;
395 	if (!index)
396 		index = &_index;
397 	return (partition && start && size && type
398 			&& partition->DiskSystem() == this && fModule
399 			&& fModule->validate_create_child
400 			&& fModule->validate_create_child(partition->PartitionData(),
401 											  start, size, type, parameters,
402 											  index));
403 }
404 
405 // CountPartitionableSpaces
406 int32
407 KPartitioningSystem::CountPartitionableSpaces(KPartition *partition)
408 {
409 	if (!partition || partition->DiskSystem() != this || !fModule)
410 		return 0;
411 	if (!fModule->get_partitionable_spaces) {
412 		// TODO: Fallback algorithm.
413 		return 0;
414 	}
415 	int32 count = 0;
416 	status_t error = fModule->get_partitionable_spaces(
417 		partition->PartitionData(), NULL, 0, &count);
418 	return (error == B_OK || error == B_BUFFER_OVERFLOW ? count : 0);
419 }
420 
421 // GetPartitionableSpaces
422 status_t
423 KPartitioningSystem::GetPartitionableSpaces(KPartition *partition,
424 											partitionable_space_data *buffer,
425 											int32 count, int32 *actualCount)
426 {
427 	if (!partition || partition->DiskSystem() != this || count > 0 && !buffer
428 		|| !actualCount || !fModule) {
429 		return B_BAD_VALUE;
430 	}
431 	if (!fModule->get_partitionable_spaces) {
432 		// TODO: Fallback algorithm.
433 		return B_ENTRY_NOT_FOUND;
434 	}
435 	return fModule->get_partitionable_spaces(partition->PartitionData(),
436 											 buffer, count, actualCount);
437 }
438 
439 // GetNextSupportedType
440 status_t
441 KPartitioningSystem::GetNextSupportedType(KPartition *partition, int32 *cookie,
442 										  char *type)
443 {
444 	if (!partition || partition->DiskSystem() != this || !cookie || !type
445 		|| !fModule) {
446 		return B_BAD_VALUE;
447 	}
448 	if (!fModule->get_next_supported_type)
449 		return B_ENTRY_NOT_FOUND;
450 	return fModule->get_next_supported_type(partition->PartitionData(), cookie,
451 											type);
452 }
453 
454 // GetTypeForContentType
455 status_t
456 KPartitioningSystem::GetTypeForContentType(const char *contentType, char *type)
457 {
458 	if (!contentType || !type || !fModule)
459 		return B_BAD_VALUE;
460 	if (!fModule->get_type_for_content_type)
461 		return B_ENTRY_NOT_FOUND;
462 	return fModule->get_type_for_content_type(contentType, type);
463 }
464 
465 // ShadowPartitionChanged
466 status_t
467 KPartitioningSystem::ShadowPartitionChanged(KPartition *partition,
468 											uint32 operation)
469 {
470 	if (!partition)
471 		return B_BAD_VALUE;
472 	if (!fModule)
473 		return B_ERROR;
474 	// If not implemented, we assume, that the partitioning system doesn't
475 	// have to make any additional changes.
476 	if (!fModule->shadow_changed)
477 		return B_OK;
478 	return fModule->shadow_changed(partition->PartitionData(), operation);
479 }
480 
481 // Repair
482 status_t
483 KPartitioningSystem::Repair(KPartition *partition, bool checkOnly,
484 							KDiskDeviceJob *job)
485 {
486 	// to be implemented
487 	return B_ERROR;
488 }
489 
490 // Resize
491 status_t
492 KPartitioningSystem::Resize(KPartition *partition, off_t size,
493 							KDiskDeviceJob *job)
494 {
495 	// check parameters
496 	if (!partition || !job || size < 0)
497 		return B_BAD_VALUE;
498 	if (!fModule->resize)
499 		return B_ENTRY_NOT_FOUND;
500 	// lock partition and open partition device
501 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
502 	KPartition *_partition = manager->ReadLockPartition(partition->ID());
503 	if (!_partition)
504 		return B_ERROR;
505 	int fd = -1;
506 	{
507 		PartitionRegistrar registrar(_partition, true);
508 		PartitionRegistrar deviceRegistrar(_partition->Device(), true);
509 		DeviceReadLocker locker(_partition->Device(), true);
510 		if (partition != _partition)
511 			return B_ERROR;
512 		status_t result = partition->Open(O_RDONLY, &fd);
513 		if (result != B_OK)
514 			return result;
515 	}
516 	// let the module do its job
517 	status_t result = fModule->resize(fd, partition->ID(), size, job->ID());
518 	// cleanup and return
519 	close(fd);
520 	return result;
521 }
522 
523 // ResizeChild
524 status_t
525 KPartitioningSystem::ResizeChild(KPartition *child, off_t size,
526 								 KDiskDeviceJob *job)
527 {
528 	// check parameters
529 	if (!child || !job || size < 0)
530 		return B_BAD_VALUE;
531 	if (!fModule->resize_child)
532 		return B_ENTRY_NOT_FOUND;
533 	// lock partition and open (parent) partition device
534 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
535 	KPartition *_partition = manager->ReadLockPartition(child->ID());
536 	if (!_partition)
537 		return B_ERROR;
538 	int fd = -1;
539 	{
540 		PartitionRegistrar registrar(_partition, true);
541 		PartitionRegistrar deviceRegistrar(_partition->Device(), true);
542 		DeviceReadLocker locker(_partition->Device(), true);
543 		if (child != _partition)
544 			return B_ERROR;
545 		if (!child->Parent())
546 			return B_BAD_VALUE;
547 		status_t result = child->Parent()->Open(O_RDONLY, &fd);
548 		if (result != B_OK)
549 			return result;
550 	}
551 	// let the module do its job
552 	status_t result = fModule->resize_child(fd, child->ID(), size, job->ID());
553 	// cleanup and return
554 	close(fd);
555 	return result;
556 }
557 
558 // Move
559 status_t
560 KPartitioningSystem::Move(KPartition *partition, off_t offset,
561 						  KDiskDeviceJob *job)
562 {
563 	// to be implemented
564 	return B_ERROR;
565 }
566 
567 // MoveChild
568 status_t
569 KPartitioningSystem::MoveChild(KPartition *child, off_t offset,
570 							   KDiskDeviceJob *job)
571 {
572 	// to be implemented
573 	return B_ERROR;
574 }
575 
576 // SetName
577 status_t
578 KPartitioningSystem::SetName(KPartition *partition, char *name,
579 							 KDiskDeviceJob *job)
580 {
581 	// to be implemented
582 	return B_ERROR;
583 }
584 
585 // SetContentName
586 status_t
587 KPartitioningSystem::SetContentName(KPartition *partition, char *name,
588 									KDiskDeviceJob *job)
589 {
590 	// to be implemented
591 	return B_ERROR;
592 }
593 
594 // SetType
595 status_t
596 KPartitioningSystem::SetType(KPartition *partition, char *type,
597 							 KDiskDeviceJob *job)
598 {
599 	// to be implemented
600 	return B_ERROR;
601 }
602 
603 // SetParameters
604 status_t
605 KPartitioningSystem::SetParameters(KPartition *partition,
606 								   const char *parameters, KDiskDeviceJob *job)
607 {
608 	// to be implemented
609 	return B_ERROR;
610 }
611 
612 // SetContentParameters
613 status_t
614 KPartitioningSystem::SetContentParameters(KPartition *partition,
615 										  const char *parameters,
616 										  KDiskDeviceJob *job)
617 {
618 	// to be implemented
619 	return B_ERROR;
620 }
621 
622 // Initialize
623 status_t
624 KPartitioningSystem::Initialize(KPartition *partition, const char *name,
625 								const char *parameters, KDiskDeviceJob *job)
626 {
627 	// to be implemented
628 	return B_ERROR;
629 }
630 
631 // CreateChild
632 status_t
633 KPartitioningSystem::CreateChild(KPartition *partition, off_t offset,
634 								 off_t size, const char *type,
635 								 const char *parameters, KDiskDeviceJob *job,
636 								 KPartition **child, partition_id childID)
637 {
638 	// to be implemented
639 	return B_ERROR;
640 }
641 
642 // DeleteChild
643 status_t
644 KPartitioningSystem::DeleteChild(KPartition *child, KDiskDeviceJob *job)
645 {
646 	// to be implemented
647 	return B_ERROR;
648 }
649 
650 // LoadModule
651 status_t
652 KPartitioningSystem::LoadModule()
653 {
654 	if (fModule)		// shouldn't happen
655 		return B_OK;
656 	return get_module(Name(), (module_info**)&fModule);
657 }
658 
659 // UnloadModule
660 void
661 KPartitioningSystem::UnloadModule()
662 {
663 	if (fModule) {
664 		put_module(fModule->module.name);
665 		fModule = NULL;
666 	}
667 }
668 
669