xref: /haiku/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp (revision b06a48ab8f30b45916a9c157b992827779182163)
1 /*
2  * Copyright 2003-2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Ingo Weinhold, bonefish@cs.tu-berlin.de
7  */
8 
9 /*! \file ddm_userland_interface.cpp
10 
11  	\brief Interface for userspace calls.
12 */
13 
14 #include <stdlib.h>
15 
16 #include <AutoDeleter.h>
17 #include <ddm_userland_interface.h>
18 #include <KDiskDevice.h>
19 #include <KDiskDeviceManager.h>
20 #include <KDiskDeviceUtils.h>
21 #include <KDiskSystem.h>
22 #include <KFileDiskDevice.h>
23 #include <syscall_args.h>
24 
25 #include "UserDataWriter.h"
26 
27 using namespace BPrivate::DiskDevice;
28 
29 // debugging
30 #define ERROR(x)
31 
32 
33 // TODO: Replace all instances, when it has been decided how to handle
34 // notifications during jobs.
35 #define DUMMY_JOB_ID	0
36 
37 
38 // TODO: Add user address checks and check return values of user_memcpy()!
39 
40 
41 // ddm_strlcpy
42 /*! \brief Wrapper around user_strlcpy() that returns a status_t
43 	indicating appropriate success or failure.
44 
45 	\param allowTruncation If \c true, does not return an error if
46 	       \a from is longer than \to. If \c false, returns \c B_NAME_TOO_LONG
47 	       if \a from is longer than \to.
48 */
49 static status_t
50 ddm_strlcpy(char *to, const char *from, size_t size,
51 	bool allowTruncation = false)
52 {
53 	ssize_t fromLen = user_strlcpy(to, from, size);
54 	if (fromLen < 0)
55 		return fromLen;
56 	if ((size_t)fromLen >= size && !allowTruncation)
57 		return B_NAME_TOO_LONG;
58 	return B_OK;
59 }
60 
61 
62 // copy_from_user_value
63 template<typename Type>
64 static inline status_t
65 copy_from_user_value(Type& value, const Type* userValue)
66 {
67 	if (!userValue)
68 		return B_BAD_VALUE;
69 
70 	if (!IS_USER_ADDRESS(userValue))
71 		return B_BAD_ADDRESS;
72 
73 	return user_memcpy(&value, userValue, sizeof(Type));
74 }
75 
76 
77 // copy_to_user_value
78 template<typename Type>
79 static inline status_t
80 copy_to_user_value(Type* userValue, const Type& value)
81 {
82 	if (!userValue)
83 		return B_BAD_VALUE;
84 
85 	if (!IS_USER_ADDRESS(userValue))
86 		return B_BAD_ADDRESS;
87 
88 	return user_memcpy(userValue, &value, sizeof(Type));
89 }
90 
91 
92 // UserStringParameter
93 template<bool kAllowsNull>
94 struct UserStringParameter {
95 	char*	value;
96 
97 	inline UserStringParameter()
98 		: value(NULL)
99 	{
100 	}
101 
102 	inline ~UserStringParameter()
103 	{
104 		free(value);
105 	}
106 
107 	inline status_t Init(const char* userValue, size_t maxSize)
108 	{
109 		if (userValue == NULL) {
110 			if (!kAllowsNull)
111 				return B_BAD_VALUE;
112 
113 			return B_OK;
114 		}
115 
116 		if (!IS_USER_ADDRESS(userValue))
117 			return B_BAD_ADDRESS;
118 
119 		value = (char*)malloc(maxSize);
120 		if (value == NULL)
121 			return B_NO_MEMORY;
122 
123 		ssize_t bytesCopied = user_strlcpy(value, userValue, maxSize);
124 		if (bytesCopied < 0)
125 			return bytesCopied;
126 
127 		if ((size_t)bytesCopied >= maxSize)
128 			return B_BUFFER_OVERFLOW;
129 
130 		return B_OK;
131 	}
132 
133 	inline operator const char*()
134 	{
135 		return value;
136 	}
137 
138 	inline operator char*()
139 	{
140 		return value;
141 	}
142 };
143 
144 
145 // UserMemoryParameter
146 template<typename Type, bool kAllowsNull>
147 struct UserMemoryParameter {
148 	Type*	value;
149 
150 	inline UserMemoryParameter()
151 		: value(NULL)
152 	{
153 	}
154 
155 	inline ~UserMemoryParameter()
156 	{
157 		free(value);
158 	}
159 
160 	inline status_t Init(const Type* userValue, size_t size)
161 	{
162 		if (userValue == NULL) {
163 			if (!kAllowsNull)
164 				return B_BAD_VALUE;
165 
166 			value = NULL;
167 			return B_OK;
168 		}
169 
170 		if (!IS_USER_ADDRESS(userValue))
171 			return B_BAD_ADDRESS;
172 
173 		value = (Type*)malloc(size);
174 		if (value == NULL)
175 			return B_NO_MEMORY;
176 
177 		return user_memcpy(value, userValue, size);
178 	}
179 
180 	inline status_t Init(const Type* userValue, size_t size, size_t maxSize)
181 	{
182 		if (size > maxSize)
183 			return B_BAD_VALUE;
184 
185 		return Init(userValue, size);
186 	}
187 };
188 
189 
190 #if 0
191 // move_descendants
192 static void
193 move_descendants(KPartition *partition, off_t moveBy)
194 {
195 	if (!partition)
196 		return;
197 	partition->SetOffset(partition->Offset() + moveBy);
198 	// move children
199 	for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++)
200 		move_descendants(child, moveBy);
201 }
202 
203 
204 // move_descendants_contents
205 static status_t
206 move_descendants_contents(KPartition *partition)
207 {
208 	if (!partition)
209 		return B_BAD_VALUE;
210 	// implicit content disk system changes
211 	KDiskSystem *diskSystem = partition->DiskSystem();
212 	if (diskSystem || partition->AlgorithmData()) {
213 		status_t error = diskSystem->ShadowPartitionChanged(partition,
214 			NULL, B_PARTITION_MOVE);
215 		if (error != B_OK)
216 			return error;
217 	}
218 	// move children's contents
219 	for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++) {
220 		status_t error = move_descendants_contents(child);
221 		if (error != B_OK)
222 			return error;
223 	}
224 	return B_OK;
225 }
226 #endif // 0
227 
228 
229 // _user_get_next_disk_device_id
230 partition_id
231 _user_get_next_disk_device_id(int32 *_cookie, size_t *neededSize)
232 {
233 	if (!_cookie)
234 		return B_BAD_VALUE;
235 	int32 cookie;
236 	user_memcpy(&cookie, _cookie, sizeof(cookie));
237 
238 	partition_id id = B_ENTRY_NOT_FOUND;
239 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
240 	// get the next device
241 	if (KDiskDevice *device = manager->RegisterNextDevice(&cookie)) {
242 		PartitionRegistrar _(device, true);
243 		id = device->ID();
244 		if (neededSize) {
245 			if (DeviceReadLocker locker = device) {
246 				// get the needed size
247 				UserDataWriter writer;
248 				device->WriteUserData(writer);
249 				status_t status = copy_to_user_value(neededSize,
250 					writer.AllocatedSize());
251 				if (status != B_OK)
252 					return status;
253 			} else {
254 				id = B_ERROR;
255 			}
256 		}
257 	}
258 	user_memcpy(_cookie, &cookie, sizeof(cookie));
259 	return id;
260 }
261 
262 
263 // _user_find_disk_device
264 partition_id
265 _user_find_disk_device(const char *_filename, size_t *neededSize)
266 {
267 	UserStringParameter<false> filename;
268 	status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
269 	if (error != B_OK)
270 		return error;
271 
272 	partition_id id = B_ENTRY_NOT_FOUND;
273 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
274 	// find the device
275 	if (KDiskDevice *device = manager->RegisterDevice(filename)) {
276 		PartitionRegistrar _(device, true);
277 		id = device->ID();
278 		if (neededSize) {
279 			if (DeviceReadLocker locker = device) {
280 				// get the needed size
281 				UserDataWriter writer;
282 				device->WriteUserData(writer);
283 				error = copy_to_user_value(neededSize, writer.AllocatedSize());
284 				if (error != B_OK)
285 					return error;
286 			} else
287 				return B_ERROR;
288 		}
289 	}
290 	return id;
291 }
292 
293 
294 // _user_find_partition
295 partition_id
296 _user_find_partition(const char *_filename, size_t *neededSize)
297 {
298 	UserStringParameter<false> filename;
299 	status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
300 	if (error != B_OK)
301 		return error;
302 
303 	partition_id id = B_ENTRY_NOT_FOUND;
304 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
305 	// find the partition
306 	if (KPartition *partition = manager->RegisterPartition(filename)) {
307 		PartitionRegistrar _(partition, true);
308 		id = partition->ID();
309 		if (neededSize) {
310 			// get and lock the partition's device
311 			KDiskDevice *device = manager->RegisterDevice(partition->ID(),
312 				false);
313 			if (!device)
314 				return B_ENTRY_NOT_FOUND;
315 			PartitionRegistrar _2(device, true);
316 			if (DeviceReadLocker locker = device) {
317 				// get the needed size
318 				UserDataWriter writer;
319 				device->WriteUserData(writer);
320 				error = copy_to_user_value(neededSize, writer.AllocatedSize());
321 				if (error != B_OK)
322 					return error;
323 			} else
324 				return B_ERROR;
325 		}
326 	}
327 	return id;
328 }
329 
330 
331 // _user_get_disk_device_data
332 /*!	\brief Writes data describing the disk device identified by ID and all
333 		   its partitions into the supplied buffer.
334 
335 	The function passes the buffer size required to hold the data back
336 	through the \a _neededSize parameter, if the device could be found at
337 	least and no serious error occured. If fails with \c B_BUFFER_OVERFLOW,
338 	if the supplied buffer is too small or a \c NULL buffer is supplied
339 	(and \c bufferSize is 0).
340 
341 	The device is identified by \a id. If \a deviceOnly is \c true, then
342 	it must be the ID of a disk device, otherwise the disk device is
343 	chosen, on which the partition \a id refers to resides.
344 
345 	\param id The ID of an arbitrary partition on the disk device (including
346 		   the disk device itself), whose data shall be returned
347 		   (if \a deviceOnly is \c false), or the ID of the disk device
348 		   itself (if \a deviceOnly is true).
349 	\param deviceOnly Specifies whether only IDs of disk devices (\c true),
350 		   or also IDs of partitions (\c false) are accepted for \a id.
351 	\param buffer The buffer into which the disk device data shall be written.
352 		   May be \c NULL.
353 	\param bufferSize The size of \a buffer.
354 	\param _neededSize Pointer to a variable into which the actually needed
355 		   buffer size is written. May be \c NULL.
356 	\return
357 	- \c B_OK: Everything went fine. The device was found and, if not \c NULL,
358 	  in \a _neededSize the actually needed buffer size is returned. And
359 	  \a buffer will contain the disk device data.
360 	- \c B_BAD_VALUE: \c NULL \a buffer, but not 0 \a bufferSize.
361 	- \c B_BUFFER_OVERFLOW: The supplied buffer was too small. \a _neededSize,
362 	  if not \c NULL, will contain the required buffer size.
363 	- \c B_NO_MEMORY: Insufficient memory to complete the operation.
364 	- \c B_ENTRY_NOT_FOUND: \a id is no valid disk device ID (if \a deviceOnly
365 	  is \c true) or not even a valid partition ID (if \a deviceOnly is
366 	  \c false).
367 	- \c B_ERROR: An unexpected error occured.
368 	- another error code...
369 */
370 status_t
371 _user_get_disk_device_data(partition_id id, bool deviceOnly,
372 	user_disk_device_data *buffer, size_t bufferSize, size_t *_neededSize)
373 {
374 	if (!buffer && bufferSize > 0)
375 		return B_BAD_VALUE;
376 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
377 	// get the device
378 	if (KDiskDevice *device = manager->RegisterDevice(id, deviceOnly)) {
379 		PartitionRegistrar _(device, true);
380 		if (DeviceReadLocker locker = device) {
381 			// do a dry run first to get the needed size
382 			UserDataWriter writer;
383 			device->WriteUserData(writer);
384 			size_t neededSize = writer.AllocatedSize();
385 			if (_neededSize) {
386 				status_t error = copy_ref_var_to_user(neededSize, _neededSize);
387 				if (error != B_OK)
388 					return error;
389 			}
390 			// if no buffer has been supplied or the buffer is too small,
391 			// then we're done
392 			if (!buffer || bufferSize < neededSize)
393 				return B_BUFFER_OVERFLOW;
394 			// otherwise allocate a kernel buffer
395 			user_disk_device_data *kernelBuffer
396 				= static_cast<user_disk_device_data*>(malloc(neededSize));
397 			if (!kernelBuffer)
398 				return B_NO_MEMORY;
399 			MemoryDeleter deleter(kernelBuffer);
400 			// write the device data into the buffer
401 			writer.SetTo(kernelBuffer, bufferSize);
402 			device->WriteUserData(writer);
403 			// sanity check
404 			if (writer.AllocatedSize() != neededSize) {
405 				ERROR(("Size of written disk device user data changed from "
406 					   "%lu to %lu while device was locked!\n"));
407 				return B_ERROR;
408 			}
409 			// relocate
410 			status_t error = writer.Relocate(buffer);
411 			if (error != B_OK)
412 				return error;
413 			// copy out
414 			if (buffer)
415 				return user_memcpy(buffer, kernelBuffer, neededSize);
416 		} else
417 			return B_ERROR;
418 	}
419 	return B_ENTRY_NOT_FOUND;
420 }
421 
422 
423 // _user_register_file_device
424 partition_id
425 _user_register_file_device(const char *_filename)
426 {
427 	UserStringParameter<false> filename;
428 	status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
429 	if (error != B_OK)
430 		return error;
431 
432 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
433 	if (ManagerLocker locker = manager) {
434 		if (KFileDiskDevice *device = manager->FindFileDevice(filename))
435 			return device->ID();
436 		return manager->CreateFileDevice(filename);
437 	}
438 	return B_ERROR;
439 }
440 
441 
442 // _user_unregister_file_device
443 status_t
444 _user_unregister_file_device(partition_id deviceID, const char *_filename)
445 {
446 	if (deviceID < 0 && !_filename)
447 		return B_BAD_VALUE;
448 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
449 	if (deviceID >= 0) {
450 		return manager->DeleteFileDevice(deviceID);
451 	} else {
452 		UserStringParameter<false> filename;
453 		status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
454 		if (error != B_OK)
455 			return error;
456 
457 		return manager->DeleteFileDevice(filename);
458 	}
459 }
460 
461 
462 // _user_get_disk_system_info
463 status_t
464 _user_get_disk_system_info(disk_system_id id, user_disk_system_info *_info)
465 {
466 	if (!_info)
467 		return B_BAD_VALUE;
468 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
469 	if (ManagerLocker locker = manager) {
470 		if (KDiskSystem *diskSystem = manager->FindDiskSystem(id)) {
471 			user_disk_system_info info;
472 			diskSystem->GetInfo(&info);
473 			user_memcpy(_info, &info, sizeof(info));
474 			return B_OK;
475 		}
476 	}
477 	return B_ENTRY_NOT_FOUND;
478 }
479 
480 
481 // _user_get_next_disk_system_info
482 status_t
483 _user_get_next_disk_system_info(int32 *_cookie, user_disk_system_info *_info)
484 {
485 	if (!_cookie || !_info)
486 		return B_BAD_VALUE;
487 	int32 cookie;
488 	user_memcpy(&cookie, _cookie, sizeof(cookie));
489 	status_t result = B_ENTRY_NOT_FOUND;
490 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
491 	if (ManagerLocker locker = manager) {
492 		if (KDiskSystem *diskSystem = manager->NextDiskSystem(&cookie)) {
493 			user_disk_system_info info;
494 			diskSystem->GetInfo(&info);
495 			user_memcpy(_info, &info, sizeof(info));
496 			result = B_OK;
497 		}
498 	}
499 	user_memcpy(_cookie, &cookie, sizeof(cookie));
500 	return result;
501 }
502 
503 
504 // _user_find_disk_system
505 status_t
506 _user_find_disk_system(const char *_name, user_disk_system_info *_info)
507 {
508 	if (!_name || !_info)
509 		return B_BAD_VALUE;
510 	char name[B_DISK_SYSTEM_NAME_LENGTH];
511 	status_t error = ddm_strlcpy(name, _name, B_DISK_SYSTEM_NAME_LENGTH);
512 	if (error)
513 		return error;
514 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
515 	if (ManagerLocker locker = manager) {
516 		if (KDiskSystem *diskSystem = manager->FindDiskSystem(name)) {
517 			user_disk_system_info info;
518 			diskSystem->GetInfo(&info);
519 			user_memcpy(_info, &info, sizeof(info));
520 			return B_OK;
521 		}
522 	}
523 	return B_ENTRY_NOT_FOUND;
524 }
525 
526 
527 // _user_defragment_partition
528 status_t
529 _user_defragment_partition(partition_id partitionID, int32* _changeCounter)
530 {
531 	// copy parameters in
532 	int32 changeCounter;
533 
534 	status_t error;
535 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
536 		return error;
537 
538 	// get the partition
539 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
540 	KPartition* partition = manager->WriteLockPartition(partitionID);
541 	if (!partition)
542 		return B_ENTRY_NOT_FOUND;
543 
544 	PartitionRegistrar registrar1(partition, true);
545 	PartitionRegistrar registrar2(partition->Device(), true);
546 	DeviceWriteLocker locker(partition->Device(), true);
547 
548 	// check change counter
549 	if (changeCounter != partition->ChangeCounter())
550 		return B_BAD_VALUE;
551 
552 	// the partition must be initialized
553 	KDiskSystem* diskSystem = partition->DiskSystem();
554 	if (!diskSystem)
555 		return B_BAD_VALUE;
556 
557 	// mark the partition busy and unlock
558 	if (!partition->CheckAndMarkBusy(false))
559 		return B_BUSY;
560 	locker.Unlock();
561 
562 	// defragment
563 	error = diskSystem->Defragment(partition, DUMMY_JOB_ID);
564 
565 	// re-lock and unmark busy
566 	locker.Lock();
567 	partition->UnmarkBusy(false);
568 
569 	if (error != B_OK)
570 		return error;
571 
572 	// return change counter
573 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
574 			!= B_OK) {
575 		return error;
576 	}
577 
578 	return B_OK;
579 }
580 
581 
582 // _user_repair_partition
583 status_t
584 _user_repair_partition(partition_id partitionID, int32* _changeCounter,
585 	bool checkOnly)
586 {
587 	// copy parameters in
588 	int32 changeCounter;
589 
590 	status_t error;
591 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
592 		return error;
593 
594 	// get the partition
595 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
596 	KPartition* partition = manager->WriteLockPartition(partitionID);
597 	if (!partition)
598 		return B_ENTRY_NOT_FOUND;
599 
600 	PartitionRegistrar registrar1(partition, true);
601 	PartitionRegistrar registrar2(partition->Device(), true);
602 	DeviceWriteLocker locker(partition->Device(), true);
603 
604 	// check change counter
605 	if (changeCounter != partition->ChangeCounter())
606 		return B_BAD_VALUE;
607 
608 	// the partition must be initialized
609 	KDiskSystem* diskSystem = partition->DiskSystem();
610 	if (!diskSystem)
611 		return B_BAD_VALUE;
612 
613 	// mark the partition busy and unlock
614 	if (!partition->CheckAndMarkBusy(false))
615 		return B_BUSY;
616 	locker.Unlock();
617 
618 	// repair/check
619 	error = diskSystem->Repair(partition, checkOnly, DUMMY_JOB_ID);
620 
621 	// re-lock and unmark busy
622 	locker.Lock();
623 	partition->UnmarkBusy(false);
624 
625 	if (error != B_OK)
626 		return error;
627 
628 	// return change counter
629 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
630 			!= B_OK) {
631 		return error;
632 	}
633 
634 	return B_OK;
635 }
636 
637 
638 // _user_resize_partition
639 status_t
640 _user_resize_partition(partition_id partitionID, int32* _changeCounter,
641 	partition_id childID, int32* _childChangeCounter, off_t size,
642 	off_t contentSize)
643 {
644 	// copy parameters in
645 	int32 changeCounter;
646 	int32 childChangeCounter;
647 
648 	status_t error;
649 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK
650 		|| (error = copy_from_user_value(childChangeCounter,
651 			_childChangeCounter)) != B_OK) {
652 		return error;
653 	}
654 
655 	// get the partition
656 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
657 	KPartition* partition = manager->WriteLockPartition(partitionID);
658 	if (!partition)
659 		return B_ENTRY_NOT_FOUND;
660 
661 	PartitionRegistrar registrar1(partition, true);
662 	PartitionRegistrar registrar2(partition->Device(), true);
663 	DeviceWriteLocker locker(partition->Device(), true);
664 
665 	// register child
666 	KPartition* child = manager->RegisterPartition(childID);
667 	if (!child)
668 		return B_ENTRY_NOT_FOUND;
669 
670 	PartitionRegistrar registrar3(child, true);
671 
672 	// check change counters
673 	if (changeCounter != partition->ChangeCounter()
674 		|| childChangeCounter != child->ChangeCounter()) {
675 		return B_BAD_VALUE;
676 	}
677 
678 	// the partition must be initialized
679 	KDiskSystem* diskSystem = partition->DiskSystem();
680 	if (!diskSystem)
681 		return B_BAD_VALUE;
682 
683 	// child must indeed be a child of partition
684 	if (child->Parent() != partition)
685 		return B_BAD_VALUE;
686 
687 	// check sizes
688 	if (size < 0 || contentSize < 0 || size < contentSize
689 		|| size > partition->ContentSize()) {
690 		return B_BAD_VALUE;
691 	}
692 
693 	// mark the partitions busy and unlock
694 	if (partition->IsBusy() || child->IsBusy())
695 		return B_BUSY;
696 	partition->SetBusy(true);
697 	child->SetBusy(true);
698 	locker.Unlock();
699 
700 	// resize contents first, if shrinking
701 	if (child->DiskSystem() && contentSize < child->ContentSize())
702 		error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID);
703 
704 	// resize the partition
705 	if (error == B_OK && size != child->Size())
706 		error = diskSystem->ResizeChild(child, size, DUMMY_JOB_ID);
707 
708 	// resize contents last, if growing
709 	if (error == B_OK && child->DiskSystem()
710 		&& contentSize > child->ContentSize()) {
711 		error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID);
712 	}
713 
714 	// re-lock and unmark busy
715 	locker.Lock();
716 	partition->SetBusy(false);
717 	child->SetBusy(false);
718 
719 	if (error != B_OK)
720 		return error;
721 
722 	// return change counters
723 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
724 			!= B_OK
725 		|| (error = copy_to_user_value(_childChangeCounter,
726 			child->ChangeCounter())) != B_OK) {
727 		return error;
728 	}
729 
730 	return B_OK;
731 }
732 
733 
734 // _user_move_partition
735 status_t
736 _user_move_partition(partition_id partitionID, int32* changeCounter,
737 	partition_id childID, int32* childChangeCounter, off_t newOffset,
738 	partition_id* descendantIDs, int32* descendantChangeCounters,
739 	int32 descendantCount)
740 {
741 #if 0
742 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
743 	// get the partition
744 	KPartition *partition = manager->WriteLockPartition(partitionID);
745 	if (!partition)
746 		return B_ENTRY_NOT_FOUND;
747 	PartitionRegistrar registrar1(partition, true);
748 	PartitionRegistrar registrar2(partition->Device(), true);
749 	DeviceWriteLocker locker(partition->Device(), true);
750 	// check the new offset
751 	if (newOffset == partition->Offset())
752 		return B_OK;
753 	off_t proposedOffset = newOffset;
754 	status_t error = validate_move_partition(partition, changeCounter,
755 		&proposedOffset, true);
756 	if (error != B_OK)
757 		return error;
758 	if (proposedOffset != newOffset)
759 		return B_BAD_VALUE;
760 	// new offset is fine -- move the thing
761 	off_t moveBy = newOffset - partition->Offset();
762 	move_descendants(partition, moveBy);
763 	partition->Changed(B_PARTITION_CHANGED_OFFSET);
764 	// implicit partitioning system changes
765 	error = partition->Parent()->DiskSystem()->ShadowPartitionChanged(
766 		partition->Parent(), partition, B_PARTITION_MOVE_CHILD);
767 	if (error != B_OK)
768 		return error;
769 	// implicit descendants' content disk system changes
770 	return move_descendants_contents(partition);
771 #endif
772 return B_BAD_VALUE;
773 }
774 
775 
776 // _user_set_partition_name
777 status_t
778 _user_set_partition_name(partition_id partitionID, int32* _changeCounter,
779 	partition_id childID, int32* _childChangeCounter, const char* _name)
780 {
781 	// copy parameters in
782 	UserStringParameter<false> name;
783 	int32 changeCounter;
784 	int32 childChangeCounter;
785 
786 	status_t error;
787 	if ((error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
788 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
789 			!= B_OK
790 		|| (error = copy_from_user_value(childChangeCounter,
791 			_childChangeCounter)) != B_OK) {
792 		return error;
793 	}
794 
795 	// get the partition
796 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
797 	KPartition* partition = manager->WriteLockPartition(partitionID);
798 	if (!partition)
799 		return B_ENTRY_NOT_FOUND;
800 
801 	PartitionRegistrar registrar1(partition, true);
802 	PartitionRegistrar registrar2(partition->Device(), true);
803 	DeviceWriteLocker locker(partition->Device(), true);
804 
805 	// register child
806 	KPartition* child = manager->RegisterPartition(childID);
807 	if (!child)
808 		return B_ENTRY_NOT_FOUND;
809 
810 	PartitionRegistrar registrar3(child, true);
811 
812 	// check change counters
813 	if (changeCounter != partition->ChangeCounter()
814 		|| childChangeCounter != child->ChangeCounter()) {
815 		return B_BAD_VALUE;
816 	}
817 
818 	// the partition must be initialized
819 	KDiskSystem* diskSystem = partition->DiskSystem();
820 	if (!diskSystem)
821 		return B_BAD_VALUE;
822 
823 	// child must indeed be a child of partition
824 	if (child->Parent() != partition)
825 		return B_BAD_VALUE;
826 
827 	// mark the partitions busy and unlock
828 	if (partition->IsBusy() || child->IsBusy())
829 		return B_BUSY;
830 	partition->SetBusy(true);
831 	child->SetBusy(true);
832 	locker.Unlock();
833 
834 	// set the child name
835 	error = diskSystem->SetName(child, name.value, DUMMY_JOB_ID);
836 
837 	// re-lock and unmark busy
838 	locker.Lock();
839 	partition->SetBusy(false);
840 	child->SetBusy(false);
841 
842 	if (error != B_OK)
843 		return error;
844 
845 	// return change counters
846 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
847 			!= B_OK
848 		|| (error = copy_to_user_value(_childChangeCounter,
849 			child->ChangeCounter())) != B_OK) {
850 		return error;
851 	}
852 
853 	return B_OK;
854 }
855 
856 
857 // _user_set_partition_content_name
858 status_t
859 _user_set_partition_content_name(partition_id partitionID,
860 	int32* _changeCounter, const char* _name)
861 {
862 	// copy parameters in
863 	UserStringParameter<true> name;
864 	int32 changeCounter;
865 
866 	status_t error;
867 	if ((error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
868 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
869 			!= B_OK) {
870 		return error;
871 	}
872 
873 	// get the partition
874 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
875 	KPartition* partition = manager->WriteLockPartition(partitionID);
876 	if (!partition)
877 		return B_ENTRY_NOT_FOUND;
878 
879 	PartitionRegistrar registrar1(partition, true);
880 	PartitionRegistrar registrar2(partition->Device(), true);
881 	DeviceWriteLocker locker(partition->Device(), true);
882 
883 	// check change counter
884 	if (changeCounter != partition->ChangeCounter())
885 		return B_BAD_VALUE;
886 
887 	// the partition must be initialized
888 	KDiskSystem* diskSystem = partition->DiskSystem();
889 	if (!diskSystem)
890 		return B_BAD_VALUE;
891 
892 	// mark the partition busy and unlock
893 	if (!partition->CheckAndMarkBusy(false))
894 		return B_BUSY;
895 	locker.Unlock();
896 
897 	// set content parameters
898 	error = diskSystem->SetContentName(partition, name.value, DUMMY_JOB_ID);
899 
900 	// re-lock and unmark busy
901 	locker.Lock();
902 	partition->UnmarkBusy(false);
903 
904 	if (error != B_OK)
905 		return error;
906 
907 	// return change counter
908 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
909 			!= B_OK) {
910 		return error;
911 	}
912 
913 	return B_OK;
914 }
915 
916 
917 // _user_set_partition_type
918 status_t
919 _user_set_partition_type(partition_id partitionID, int32* _changeCounter,
920 	partition_id childID, int32* _childChangeCounter, const char* _type)
921 {
922 	// copy parameters in
923 	UserStringParameter<false> type;
924 	int32 changeCounter;
925 	int32 childChangeCounter;
926 
927 	status_t error;
928 	if ((error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH)) != B_OK
929 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
930 			!= B_OK
931 		|| (error = copy_from_user_value(childChangeCounter,
932 			_childChangeCounter)) != B_OK) {
933 		return error;
934 	}
935 
936 	// get the partition
937 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
938 	KPartition* partition = manager->WriteLockPartition(partitionID);
939 	if (!partition)
940 		return B_ENTRY_NOT_FOUND;
941 
942 	PartitionRegistrar registrar1(partition, true);
943 	PartitionRegistrar registrar2(partition->Device(), true);
944 	DeviceWriteLocker locker(partition->Device(), true);
945 
946 	// register child
947 	KPartition* child = manager->RegisterPartition(childID);
948 	if (!child)
949 		return B_ENTRY_NOT_FOUND;
950 
951 	PartitionRegistrar registrar3(child, true);
952 
953 	// check change counters
954 	if (changeCounter != partition->ChangeCounter()
955 		|| childChangeCounter != child->ChangeCounter()) {
956 		return B_BAD_VALUE;
957 	}
958 
959 	// the partition must be initialized
960 	KDiskSystem* diskSystem = partition->DiskSystem();
961 	if (!diskSystem)
962 		return B_BAD_VALUE;
963 
964 	// child must indeed be a child of partition
965 	if (child->Parent() != partition)
966 		return B_BAD_VALUE;
967 
968 	// mark the partition busy and unlock
969 	if (partition->IsBusy() || child->IsBusy())
970 		return B_BUSY;
971 	partition->SetBusy(true);
972 	child->SetBusy(true);
973 	locker.Unlock();
974 
975 	// set the child type
976 	error = diskSystem->SetType(child, type.value, DUMMY_JOB_ID);
977 
978 	// re-lock and unmark busy
979 	locker.Lock();
980 	partition->SetBusy(false);
981 	child->SetBusy(false);
982 
983 	if (error != B_OK)
984 		return error;
985 
986 	// return change counters
987 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
988 			!= B_OK
989 		|| (error = copy_to_user_value(_childChangeCounter,
990 			child->ChangeCounter())) != B_OK) {
991 		return error;
992 	}
993 
994 	return B_OK;
995 }
996 
997 
998 // _user_set_partition_parameters
999 status_t
1000 _user_set_partition_parameters(partition_id partitionID, int32* _changeCounter,
1001 	partition_id childID, int32* _childChangeCounter, const char* _parameters,
1002 	size_t parametersSize)
1003 {
1004 	// copy parameters in
1005 	UserMemoryParameter<char, true> parameters;
1006 	int32 changeCounter;
1007 	int32 childChangeCounter;
1008 
1009 	status_t error;
1010 	if ((error = parameters.Init(_parameters, parametersSize,
1011 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1012 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1013 			!= B_OK
1014 		|| (error = copy_from_user_value(childChangeCounter,
1015 			_childChangeCounter)) != B_OK) {
1016 		return error;
1017 	}
1018 
1019 	// get the partition
1020 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1021 	KPartition* partition = manager->WriteLockPartition(partitionID);
1022 	if (!partition)
1023 		return B_ENTRY_NOT_FOUND;
1024 
1025 	PartitionRegistrar registrar1(partition, true);
1026 	PartitionRegistrar registrar2(partition->Device(), true);
1027 	DeviceWriteLocker locker(partition->Device(), true);
1028 
1029 	// register child
1030 	KPartition* child = manager->RegisterPartition(childID);
1031 	if (!child)
1032 		return B_ENTRY_NOT_FOUND;
1033 
1034 	PartitionRegistrar registrar3(child, true);
1035 
1036 	// check change counters
1037 	if (changeCounter != partition->ChangeCounter()
1038 		|| childChangeCounter != child->ChangeCounter()) {
1039 		return B_BAD_VALUE;
1040 	}
1041 
1042 	// the partition must be initialized
1043 	KDiskSystem* diskSystem = partition->DiskSystem();
1044 	if (!diskSystem)
1045 		return B_BAD_VALUE;
1046 
1047 	// child must indeed be a child of partition
1048 	if (child->Parent() != partition)
1049 		return B_BAD_VALUE;
1050 
1051 	// mark the partition busy and unlock
1052 	if (partition->IsBusy() || child->IsBusy())
1053 		return B_BUSY;
1054 	partition->SetBusy(true);
1055 	child->SetBusy(true);
1056 	locker.Unlock();
1057 
1058 	// set the child parameters
1059 	error = diskSystem->SetParameters(child, parameters.value, DUMMY_JOB_ID);
1060 
1061 	// re-lock and unmark busy
1062 	locker.Lock();
1063 	partition->SetBusy(false);
1064 	child->SetBusy(false);
1065 
1066 	if (error != B_OK)
1067 		return error;
1068 
1069 	// return change counters
1070 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1071 			!= B_OK
1072 		|| (error = copy_to_user_value(_childChangeCounter,
1073 			child->ChangeCounter())) != B_OK) {
1074 		return error;
1075 	}
1076 
1077 	return B_OK;
1078 }
1079 
1080 
1081 // _user_set_partition_content_parameters
1082 status_t
1083 _user_set_partition_content_parameters(partition_id partitionID,
1084 	int32* _changeCounter, const char* _parameters, size_t parametersSize)
1085 {
1086 	// copy parameters in
1087 	UserMemoryParameter<char, true> parameters;
1088 	int32 changeCounter;
1089 
1090 	status_t error;
1091 	if ((error = parameters.Init(_parameters, parametersSize,
1092 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1093 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1094 			!= B_OK) {
1095 		return error;
1096 	}
1097 
1098 	// get the partition
1099 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1100 	KPartition* partition = manager->WriteLockPartition(partitionID);
1101 	if (!partition)
1102 		return B_ENTRY_NOT_FOUND;
1103 
1104 	PartitionRegistrar registrar1(partition, true);
1105 	PartitionRegistrar registrar2(partition->Device(), true);
1106 	DeviceWriteLocker locker(partition->Device(), true);
1107 
1108 	// check change counter
1109 	if (changeCounter != partition->ChangeCounter())
1110 		return B_BAD_VALUE;
1111 
1112 	// the partition must be initialized
1113 	KDiskSystem* diskSystem = partition->DiskSystem();
1114 	if (!diskSystem)
1115 		return B_BAD_VALUE;
1116 
1117 	// mark the partition busy and unlock
1118 	if (!partition->CheckAndMarkBusy(true))
1119 		return B_BUSY;
1120 	locker.Unlock();
1121 
1122 	// set content parameters
1123 	error = diskSystem->SetContentParameters(partition, parameters.value,
1124 		DUMMY_JOB_ID);
1125 
1126 	// re-lock and unmark busy
1127 	locker.Lock();
1128 	partition->UnmarkBusy(true);
1129 
1130 	if (error != B_OK)
1131 		return error;
1132 
1133 	// return change counter
1134 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1135 			!= B_OK) {
1136 		return error;
1137 	}
1138 
1139 	return B_OK;
1140 }
1141 
1142 
1143 // _user_initialize_partition
1144 status_t
1145 _user_initialize_partition(partition_id partitionID, int32* _changeCounter,
1146 	const char* _diskSystemName, const char* _name, const char* _parameters,
1147 	size_t parametersSize)
1148 {
1149 	// copy parameters in
1150 	UserStringParameter<false> diskSystemName;
1151 	UserStringParameter<true> name;
1152 	UserMemoryParameter<char, true> parameters;
1153 	int32 changeCounter;
1154 
1155 	status_t error;
1156 	if ((error = diskSystemName.Init(_diskSystemName,
1157 			B_DISK_SYSTEM_NAME_LENGTH)) != B_OK
1158 		|| (error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
1159 		|| (error = parameters.Init(_parameters, parametersSize,
1160 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1161 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1162 			!= B_OK) {
1163 		return error;
1164 	}
1165 
1166 	// get the partition
1167 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1168 	KPartition* partition = manager->WriteLockPartition(partitionID);
1169 	if (!partition)
1170 		return B_ENTRY_NOT_FOUND;
1171 
1172 	PartitionRegistrar registrar1(partition, true);
1173 	PartitionRegistrar registrar2(partition->Device(), true);
1174 	DeviceWriteLocker locker(partition->Device(), true);
1175 
1176 	// check change counter
1177 	if (changeCounter != partition->ChangeCounter())
1178 		return B_BAD_VALUE;
1179 
1180 	// the partition must be uninitialized
1181 	if (partition->DiskSystem())
1182 		return B_BAD_VALUE;
1183 
1184 	// load the new disk system
1185 	KDiskSystem *diskSystem = manager->LoadDiskSystem(diskSystemName.value,
1186 		true);
1187 	if (!diskSystem)
1188 		return B_ENTRY_NOT_FOUND;
1189 	DiskSystemLoader loader(diskSystem, true);
1190 
1191 	// mark the partition busy and unlock
1192 	if (!partition->CheckAndMarkBusy(true))
1193 		return B_BUSY;
1194 	locker.Unlock();
1195 
1196 	// let the disk system initialize the partition
1197 	error = diskSystem->Initialize(partition, name.value, parameters.value,
1198 		DUMMY_JOB_ID);
1199 
1200 	// re-lock and unmark busy
1201 	locker.Lock();
1202 	partition->UnmarkBusy(true);
1203 
1204 	if (error != B_OK)
1205 		return error;
1206 
1207 	partition->SetDiskSystem(diskSystem);
1208 
1209 	// return change counter
1210 	error = copy_to_user_value(_changeCounter, partition->ChangeCounter());
1211 	if (error != B_OK)
1212 		return error;
1213 
1214 	return B_OK;
1215 }
1216 
1217 
1218 // _user_uninitialize_partition
1219 status_t
1220 _user_uninitialize_partition(partition_id partitionID, int32* _changeCounter)
1221 {
1222 	// copy parameters in
1223 	int32 changeCounter;
1224 
1225 	status_t error;
1226 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
1227 		return error;
1228 
1229 	// get the partition
1230 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1231 	KPartition* partition = manager->WriteLockPartition(partitionID);
1232 	if (!partition)
1233 		return B_ENTRY_NOT_FOUND;
1234 
1235 	PartitionRegistrar registrar1(partition, true);
1236 	PartitionRegistrar registrar2(partition->Device(), true);
1237 	DeviceWriteLocker locker(partition->Device(), true);
1238 
1239 	// check change counter
1240 	if (changeCounter != partition->ChangeCounter())
1241 		return B_BAD_VALUE;
1242 
1243 	// the partition must be initialized
1244 	if (!partition->DiskSystem())
1245 		return B_BAD_VALUE;
1246 
1247 	// check busy
1248 	if (!partition->CheckAndMarkBusy(true))
1249 		return B_BUSY;
1250 
1251 // TODO: We should also check, if any partition is mounted!
1252 
1253 	// uninitialize
1254 	error = partition->UninitializeContents(true);
1255 
1256 	partition->UnmarkBusy(true);
1257 
1258 	if (error != B_OK)
1259 		return error;
1260 
1261 	// return change counter
1262 	error = copy_to_user_value(_changeCounter, partition->ChangeCounter());
1263 	if (error != B_OK)
1264 		return error;
1265 
1266 	return B_OK;
1267 }
1268 
1269 
1270 // _user_create_child_partition
1271 status_t
1272 _user_create_child_partition(partition_id partitionID, int32* _changeCounter,
1273 	off_t offset, off_t size, const char* _type, const char* _name,
1274 	const char* _parameters, size_t parametersSize, partition_id* childID,
1275 	int32* childChangeCounter)
1276 
1277 {
1278 	// copy parameters in
1279 	UserStringParameter<false> type;
1280 	UserStringParameter<true> name;
1281 	UserMemoryParameter<char, true> parameters;
1282 	int32 changeCounter;
1283 
1284 	status_t error;
1285 	if ((error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH)) != B_OK
1286 		|| (error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
1287 		|| (error = parameters.Init(_parameters, parametersSize,
1288 			B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1289 		|| (error = copy_from_user_value(changeCounter, _changeCounter))
1290 			!= B_OK) {
1291 		return error;
1292 	}
1293 
1294 	// get the partition
1295 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1296 	KPartition* partition = manager->WriteLockPartition(partitionID);
1297 	if (!partition)
1298 		return B_ENTRY_NOT_FOUND;
1299 
1300 	PartitionRegistrar registrar1(partition, true);
1301 	PartitionRegistrar registrar2(partition->Device(), true);
1302 	DeviceWriteLocker locker(partition->Device(), true);
1303 
1304 	// check change counter
1305 	if (changeCounter != partition->ChangeCounter())
1306 		return B_BAD_VALUE;
1307 
1308 	// the partition must be initialized
1309 	KDiskSystem* diskSystem = partition->DiskSystem();
1310 	if (!diskSystem)
1311 		return B_BAD_VALUE;
1312 
1313 	// mark the partition busy and unlock
1314 	if (!partition->CheckAndMarkBusy(false))
1315 		return B_BUSY;
1316 	locker.Unlock();
1317 
1318 	// create the child
1319 	KPartition *child = NULL;
1320 	error = diskSystem->CreateChild(partition, offset, size, type.value,
1321 		name.value, parameters.value, DUMMY_JOB_ID, &child, -1);
1322 
1323 	// re-lock and unmark busy
1324 	locker.Lock();
1325 	partition->UnmarkBusy(false);
1326 
1327 	if (error != B_OK)
1328 		return error;
1329 
1330 	if (child == NULL)
1331 		return B_ERROR;
1332 
1333 	child->UnmarkBusy(true);
1334 
1335 	// return change counter and child ID
1336 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1337 			!= B_OK
1338 		|| (error = copy_to_user_value(childID, child->ID())) != B_OK) {
1339 		return error;
1340 	}
1341 
1342 	return B_OK;
1343 }
1344 
1345 
1346 // _user_delete_child_partition
1347 status_t
1348 _user_delete_child_partition(partition_id partitionID, int32* _changeCounter,
1349 	partition_id childID, int32 childChangeCounter)
1350 {
1351 	// copy parameters in
1352 	int32 changeCounter;
1353 
1354 	status_t error;
1355 	if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
1356 		return error;
1357 
1358 	// get the partition
1359 	KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1360 	KPartition* partition = manager->WriteLockPartition(partitionID);
1361 	if (!partition)
1362 		return B_ENTRY_NOT_FOUND;
1363 
1364 	PartitionRegistrar registrar1(partition, true);
1365 	PartitionRegistrar registrar2(partition->Device(), true);
1366 	DeviceWriteLocker locker(partition->Device(), true);
1367 
1368 	// register child
1369 	KPartition* child = manager->RegisterPartition(childID);
1370 	if (!child)
1371 		return B_ENTRY_NOT_FOUND;
1372 
1373 	PartitionRegistrar registrar3(child, true);
1374 
1375 	// check change counters
1376 	if (changeCounter != partition->ChangeCounter()
1377 		|| childChangeCounter != child->ChangeCounter()) {
1378 		return B_BAD_VALUE;
1379 	}
1380 
1381 	// the partition must be initialized
1382 	KDiskSystem* diskSystem = partition->DiskSystem();
1383 	if (!diskSystem)
1384 		return B_BAD_VALUE;
1385 
1386 	// child must indeed be a child of partition
1387 	if (child->Parent() != partition)
1388 		return B_BAD_VALUE;
1389 
1390 	// mark the partition and child busy and unlock
1391 	if (partition->IsBusy() || !child->CheckAndMarkBusy(true))
1392 		return B_BUSY;
1393 	partition->SetBusy(true);
1394 	locker.Unlock();
1395 
1396 	// delete the child
1397 	error = diskSystem->DeleteChild(child, DUMMY_JOB_ID);
1398 
1399 	// re-lock and unmark busy
1400 	locker.Lock();
1401 	partition->SetBusy(false);
1402 	child->UnmarkBusy(true);
1403 
1404 	if (error != B_OK)
1405 		return error;
1406 
1407 	// return change counter
1408 	if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1409 			!= B_OK) {
1410 		return error;
1411 	}
1412 
1413 	return B_OK;
1414 }
1415