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