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