xref: /haiku/src/system/kernel/disk_device_manager/ddm_userland_interface.cpp (revision bf95c9aee6c36516e5e98a4f8953659c402bbf74)
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 <KDiskDeviceJob.h>
12 #include <KDiskDeviceJobQueue.h>
13 #include <KDiskDeviceManager.h>
14 #include <KDiskDeviceUtils.h>
15 #include <KDiskSystem.h>
16 #include <KFileDiskDevice.h>
17 #include <KShadowPartition.h>
18 #include <syscall_args.h>
19 
20 #include "ddm_operation_validation.h"
21 #include "KDiskDeviceJobGenerator.h"
22 #include "UserDataWriter.h"
23 
24 using namespace BPrivate::DiskDevice;
25 
26 // debugging
27 #define ERROR(x)
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 // move_descendants
55 static void
56 move_descendants(KPartition *partition, off_t moveBy)
57 {
58 	if (!partition)
59 		return;
60 	partition->SetOffset(partition->Offset() + moveBy);
61 	// move children
62 	for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++)
63 		move_descendants(child, moveBy);
64 }
65 
66 
67 // move_descendants_contents
68 static status_t
69 move_descendants_contents(KPartition *partition)
70 {
71 	if (!partition)
72 		return B_BAD_VALUE;
73 	// implicit content disk system changes
74 	KDiskSystem *diskSystem = partition->DiskSystem();
75 	if (diskSystem || partition->AlgorithmData()) {
76 		status_t error = diskSystem->ShadowPartitionChanged(partition,
77 			NULL, B_PARTITION_MOVE);
78 		if (error != B_OK)
79 			return error;
80 	}
81 	// move children's contents
82 	for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++) {
83 		status_t error = move_descendants_contents(child);
84 		if (error != B_OK)
85 			return error;
86 	}
87 	return B_OK;
88 }
89 
90 
91 // _user_get_next_disk_device_id
92 partition_id
93 _user_get_next_disk_device_id(int32 *_cookie, size_t *neededSize)
94 {
95 	if (!_cookie)
96 		return B_BAD_VALUE;
97 	int32 cookie;
98 	user_memcpy(&cookie, _cookie, sizeof(cookie));
99 
100 	partition_id id = B_ENTRY_NOT_FOUND;
101 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
102 	// get the next device
103 	if (KDiskDevice *device = manager->RegisterNextDevice(&cookie)) {
104 		PartitionRegistrar _(device, true);
105 		id = device->ID();
106 		if (neededSize) {
107 			if (DeviceReadLocker locker = device) {
108 				// get the needed size
109 				UserDataWriter writer;
110 				device->WriteUserData(writer, false);
111 				*neededSize = writer.AllocatedSize();
112 			} else {
113 				id = B_ERROR;
114 			}
115 		}
116 	}
117 	user_memcpy(_cookie, &cookie, sizeof(cookie));
118 	return id;
119 }
120 
121 
122 // _user_find_disk_device
123 partition_id
124 _user_find_disk_device(const char *_filename, size_t *neededSize)
125 {
126 	if (!_filename)
127 		return B_BAD_VALUE;
128 
129 	char filename[B_PATH_NAME_LENGTH];
130 	status_t error = ddm_strlcpy(filename, _filename, B_PATH_NAME_LENGTH);
131 	if (error)
132 		return error;
133 
134 	partition_id id = B_ENTRY_NOT_FOUND;
135 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
136 	// find the device
137 	if (KDiskDevice *device = manager->RegisterDevice(filename)) {
138 		PartitionRegistrar _(device, true);
139 		id = device->ID();
140 		if (neededSize) {
141 			if (DeviceReadLocker locker = device) {
142 				// get the needed size
143 				UserDataWriter writer;
144 				device->WriteUserData(writer, false);
145 				*neededSize = writer.AllocatedSize();
146 			} else
147 				return B_ERROR;
148 		}
149 	}
150 	return id;
151 }
152 
153 
154 // _user_find_partition
155 partition_id
156 _user_find_partition(const char *_filename, size_t *neededSize)
157 {
158 	if (!_filename)
159 		return B_BAD_VALUE;
160 
161 	char filename[B_PATH_NAME_LENGTH];
162 	status_t error = ddm_strlcpy(filename, _filename, B_PATH_NAME_LENGTH);
163 	if (error)
164 		return error;
165 
166 	partition_id id = B_ENTRY_NOT_FOUND;
167 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
168 	// find the partition
169 	if (KPartition *partition = manager->RegisterPartition(filename)) {
170 		PartitionRegistrar _(partition, true);
171 		id = partition->ID();
172 		if (neededSize) {
173 			// get and lock the partition's device
174 			KDiskDevice *device = manager->RegisterDevice(partition->ID());
175 			if (!device)
176 				return B_ENTRY_NOT_FOUND;
177 			PartitionRegistrar _2(device, true);
178 			if (DeviceReadLocker locker = device) {
179 				// get the needed size
180 				UserDataWriter writer;
181 				device->WriteUserData(writer, false);
182 				*neededSize = writer.AllocatedSize();
183 			} else
184 				return B_ERROR;
185 		}
186 	}
187 	return id;
188 }
189 
190 
191 // _user_get_disk_device_data
192 /*!	\brief Writes data describing the disk device identified by ID and all
193 		   its partitions into the supplied buffer.
194 
195 	The function passes the buffer size required to hold the data back
196 	through the \a _neededSize parameter, if the device could be found at
197 	least and no serious error occured. If fails with \c B_BUFFER_OVERFLOW,
198 	if the supplied buffer is too small or a \c NULL buffer is supplied
199 	(and \c bufferSize is 0).
200 
201 	The device is identified by \a id. If \a deviceOnly is \c true, then
202 	it must be the ID of a disk device, otherwise the disk device is
203 	chosen, on which the partition \a id refers to resides.
204 
205 	\param id The ID of an arbitrary partition on the disk device (including
206 		   the disk device itself), whose data shall be returned
207 		   (if \a deviceOnly is \c false), or the ID of the disk device
208 		   itself (if \a deviceOnly is true).
209 	\param deviceOnly Specifies whether only IDs of disk devices (\c true),
210 		   or also IDs of partitions (\c false) are accepted for \a id.
211 	\param shadow If \c true, the data of the shadow disk device is returned,
212 		   otherwise of the physical device. If there is no shadow device,
213 		   the parameter is ignored.
214 	\param buffer The buffer into which the disk device data shall be written.
215 		   May be \c NULL.
216 	\param bufferSize The size of \a buffer.
217 	\param _neededSize Pointer to a variable into which the actually needed
218 		   buffer size is written. May be \c NULL.
219 	\return
220 	- \c B_OK: Everything went fine. The device was found and, if not \c NULL,
221 	  in \a _neededSize the actually needed buffer size is returned. And
222 	  \a buffer will contain the disk device data.
223 	- \c B_BAD_VALUE: \c NULL \a buffer, but not 0 \a bufferSize.
224 	- \c B_BUFFER_OVERFLOW: The supplied buffer was too small. \a _neededSize,
225 	  if not \c NULL, will contain the required buffer size.
226 	- \c B_NO_MEMORY: Insufficient memory to complete the operation.
227 	- \c B_ENTRY_NOT_FOUND: \a id is no valid disk device ID (if \a deviceOnly
228 	  is \c true) or not even a valid partition ID (if \a deviceOnly is
229 	  \c false).
230 	- \c B_ERROR: An unexpected error occured.
231 	- another error code...
232 */
233 status_t
234 _user_get_disk_device_data(partition_id id, bool deviceOnly, bool shadow,
235 	user_disk_device_data *buffer, size_t bufferSize, size_t *_neededSize)
236 {
237 	if (!buffer && bufferSize > 0)
238 		return B_BAD_VALUE;
239 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
240 	// get the device
241 	if (KDiskDevice *device = manager->RegisterDevice(id, deviceOnly)) {
242 		PartitionRegistrar _(device, true);
243 		if (DeviceReadLocker locker = device) {
244 			// do a dry run first to get the needed size
245 			UserDataWriter writer;
246 			device->WriteUserData(writer, shadow);
247 			size_t neededSize = writer.AllocatedSize();
248 			if (_neededSize) {
249 				status_t error = copy_ref_var_to_user(neededSize, _neededSize);
250 				if (error != B_OK)
251 					return error;
252 			}
253 			// if no buffer has been supplied or the buffer is too small,
254 			// then we're done
255 			if (!buffer || bufferSize < neededSize)
256 				return B_BUFFER_OVERFLOW;
257 			// otherwise allocate a kernel buffer
258 			user_disk_device_data *kernelBuffer
259 				= static_cast<user_disk_device_data*>(malloc(neededSize));
260 			if (!kernelBuffer)
261 				return B_NO_MEMORY;
262 			MemoryDeleter deleter(kernelBuffer);
263 			// write the device data into the buffer
264 			writer.SetTo(kernelBuffer, bufferSize);
265 			device->WriteUserData(writer, shadow);
266 			// sanity check
267 			if (writer.AllocatedSize() != neededSize) {
268 				ERROR(("Size of written disk device user data changed from "
269 					   "%lu to %lu while device was locked!\n"));
270 				return B_ERROR;
271 			}
272 			// relocate
273 			status_t error = writer.Relocate(buffer);
274 			if (error != B_OK)
275 				return error;
276 			// copy out
277 			if (buffer)
278 				return user_memcpy(buffer, kernelBuffer, neededSize);
279 		} else
280 			return B_ERROR;
281 	}
282 	return B_ENTRY_NOT_FOUND;
283 }
284 
285 
286 // _user_get_partitionable_spaces
287 status_t
288 _user_get_partitionable_spaces(partition_id partitionID, int32 changeCounter,
289 	partitionable_space_data *_buffer, int32 count, int32 *_actualCount)
290 {
291 	if (count > 0 && !_buffer)
292 		return B_BAD_VALUE;
293 
294 	if (count > 0 && !IS_USER_ADDRESS(_buffer)
295 		|| _actualCount && !IS_USER_ADDRESS(_actualCount)) {
296 		return B_BAD_ADDRESS;
297 	}
298 
299 	// allocate buffer
300 	int32 bufferSize = count * sizeof(partitionable_space_data);
301 	partitionable_space_data *buffer = NULL;
302 	MemoryDeleter bufferDeleter;
303 	if (count > 0) {
304 		buffer = (partitionable_space_data*)malloc(bufferSize);
305 		if (!buffer)
306 			return B_NO_MEMORY;
307 		bufferDeleter.SetTo(buffer);
308 	}
309 
310 	status_t error = B_OK;
311 
312 	// get the partition
313 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
314 	KPartition *partition = manager->ReadLockPartition(partitionID);
315 	if (!partition)
316 		return B_ENTRY_NOT_FOUND;
317 
318 	PartitionRegistrar registrar1(partition, true);
319 	PartitionRegistrar registrar2(partition->Device(), true);
320 	DeviceReadLocker locker(partition->Device(), true);
321 
322 	if (!check_shadow_partition(partition, changeCounter))
323 		return B_BAD_VALUE;
324 
325 	// get the disk system
326 	KDiskSystem *diskSystem = partition->DiskSystem();
327 	if (!diskSystem)
328 		return B_ENTRY_NOT_FOUND;
329 
330 	// get the info
331 	int32 actualCount;
332 	error = diskSystem->GetPartitionableSpaces(partition, buffer, count,
333 		&actualCount);
334 
335 	// copy out
336 	if (_actualCount)
337 		user_memcpy(_actualCount, &actualCount, sizeof(actualCount));
338 			// copy even on error
339 
340 	if (error == B_OK && buffer)
341 		user_memcpy(_buffer, buffer, bufferSize);
342 
343 	return error;
344 }
345 
346 
347 // _user_register_file_device
348 partition_id
349 _user_register_file_device(const char *_filename)
350 {
351 	if (!_filename)
352 		return B_BAD_VALUE;
353 	char filename[B_PATH_NAME_LENGTH];
354 	status_t error = ddm_strlcpy(filename, _filename, B_PATH_NAME_LENGTH);
355 	if (error)
356 		return error;
357 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
358 	if (ManagerLocker locker = manager) {
359 		if (KFileDiskDevice *device = manager->FindFileDevice(filename))
360 			return device->ID();
361 		return manager->CreateFileDevice(filename);
362 	}
363 	return B_ERROR;
364 }
365 
366 
367 // _user_unregister_file_device
368 status_t
369 _user_unregister_file_device(partition_id deviceID, const char *_filename)
370 {
371 	if (deviceID < 0 && !_filename)
372 		return B_BAD_VALUE;
373 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
374 	if (deviceID >= 0) {
375 		return manager->DeleteFileDevice(deviceID);
376 	} else {
377 		char filename[B_PATH_NAME_LENGTH];
378 		status_t error = ddm_strlcpy(filename, _filename, B_PATH_NAME_LENGTH);
379 		if (error)
380 			return error;
381 		return manager->DeleteFileDevice(filename);
382 	}
383 }
384 
385 
386 // _user_get_disk_system_info
387 status_t
388 _user_get_disk_system_info(disk_system_id id, user_disk_system_info *_info)
389 {
390 	if (!_info)
391 		return B_BAD_VALUE;
392 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
393 	if (ManagerLocker locker = manager) {
394 		if (KDiskSystem *diskSystem = manager->FindDiskSystem(id)) {
395 			user_disk_system_info info;
396 			diskSystem->GetInfo(&info);
397 			user_memcpy(_info, &info, sizeof(info));
398 			return B_OK;
399 		}
400 	}
401 	return B_ENTRY_NOT_FOUND;
402 }
403 
404 
405 // _user_get_next_disk_system_info
406 status_t
407 _user_get_next_disk_system_info(int32 *_cookie, user_disk_system_info *_info)
408 {
409 	if (!_cookie || !_info)
410 		return B_BAD_VALUE;
411 	int32 cookie;
412 	user_memcpy(&cookie, _cookie, sizeof(cookie));
413 	status_t result = B_ENTRY_NOT_FOUND;
414 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
415 	if (ManagerLocker locker = manager) {
416 		if (KDiskSystem *diskSystem = manager->NextDiskSystem(&cookie)) {
417 			user_disk_system_info info;
418 			diskSystem->GetInfo(&info);
419 			user_memcpy(_info, &info, sizeof(info));
420 			result = B_OK;
421 		}
422 	}
423 	user_memcpy(_cookie, &cookie, sizeof(cookie));
424 	return result;
425 }
426 
427 
428 // _user_find_disk_system
429 status_t
430 _user_find_disk_system(const char *_name, user_disk_system_info *_info)
431 {
432 	if (!_name || !_info)
433 		return B_BAD_VALUE;
434 	char name[B_DISK_SYSTEM_NAME_LENGTH];
435 	status_t error = ddm_strlcpy(name, _name, B_DISK_SYSTEM_NAME_LENGTH);
436 	if (error)
437 		return error;
438 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
439 	if (ManagerLocker locker = manager) {
440 		if (KDiskSystem *diskSystem = manager->FindDiskSystem(name)) {
441 			user_disk_system_info info;
442 			diskSystem->GetInfo(&info);
443 			user_memcpy(_info, &info, sizeof(info));
444 			return B_OK;
445 		}
446 	}
447 	return B_ENTRY_NOT_FOUND;
448 }
449 
450 
451 // _user_supports_defragmenting_partition
452 bool
453 _user_supports_defragmenting_partition(partition_id partitionID,
454 	int32 changeCounter, bool *_whileMounted)
455 {
456 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
457 	// get the partition
458 	KPartition *partition = manager->ReadLockPartition(partitionID);
459 	if (!partition)
460 		return false;
461 	PartitionRegistrar registrar1(partition, true);
462 	PartitionRegistrar registrar2(partition->Device(), true);
463 	DeviceReadLocker locker(partition->Device(), true);
464 	bool whileMounted;
465 	bool result = validate_defragment_partition(partition, changeCounter,
466 		&whileMounted) == B_OK;
467 	if (result && _whileMounted)
468 		user_memcpy(_whileMounted, &whileMounted, sizeof(whileMounted));
469 	return result;
470 }
471 
472 
473 // _user_supports_repairing_partition
474 bool
475 _user_supports_repairing_partition(partition_id partitionID,
476 	int32 changeCounter, bool checkOnly, bool *_whileMounted)
477 {
478 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
479 	// get the partition
480 	KPartition *partition = manager->ReadLockPartition(partitionID);
481 	if (!partition)
482 		return false;
483 	PartitionRegistrar registrar1(partition, true);
484 	PartitionRegistrar registrar2(partition->Device(), true);
485 	DeviceReadLocker locker(partition->Device(), true);
486 	bool whileMounted;
487 	bool result = validate_repair_partition(partition, changeCounter, checkOnly,
488 		&whileMounted) == B_OK;
489 	if (result && _whileMounted)
490 		user_memcpy(_whileMounted, &whileMounted, sizeof(whileMounted));
491 	return result;
492 }
493 
494 
495 // _user_supports_resizing_partition
496 bool
497 _user_supports_resizing_partition(partition_id partitionID, int32 changeCounter,
498 	bool *_canResizeContents, bool *_whileMounted)
499 {
500 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
501 
502 	// get the partition
503 	KPartition *partition = manager->ReadLockPartition(partitionID);
504 	if (!partition)
505 		return false;
506 	PartitionRegistrar registrar1(partition, true);
507 	PartitionRegistrar registrar2(partition->Device(), true);
508 	DeviceReadLocker locker(partition->Device(), true);
509 	if (!check_shadow_partition(partition, changeCounter)
510 		|| !partition->Parent()) {
511 		return false;
512 	}
513 	if (partition->Parent()->IsBusy()
514 		|| partition->Parent()->IsDescendantBusy()) {
515 		return false;
516 	}
517 
518 	// get the parent disk system
519 	KDiskSystem *parentDiskSystem = partition->Parent()->DiskSystem();
520 	if (!parentDiskSystem)
521 		return false;
522 	bool result = parentDiskSystem->SupportsChildOperations(partition,
523 		B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD);
524 	if (!result)
525 		return false;
526 
527 	// get the child disk system
528 	KDiskSystem *childDiskSystem = partition->DiskSystem();
529 	if (_canResizeContents) {
530 		bool canResizeContents = false;
531 		bool whileMounted = false;
532 		if (childDiskSystem) {
533 			uint32 operations = childDiskSystem->GetSupportedOperations(
534 				partition, B_DISK_SYSTEM_SUPPORTS_RESIZING
535 					| B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED);
536 
537 			if (operations & B_DISK_SYSTEM_SUPPORTS_RESIZING) {
538 				canResizeContents = true;
539 				if (operations & B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED)
540 					whileMounted = true;
541 			}
542 		}
543 
544 		user_memcpy(_canResizeContents, &canResizeContents, sizeof(canResizeContents));
545 		if (_whileMounted)
546 			user_memcpy(_whileMounted, &whileMounted, sizeof(whileMounted));
547 	}
548 // TODO: Currently we report that we cannot resize the contents, if the
549 // partition's disk system is unknown. I found this more logical. It doesn't
550 // really matter, though, since the API user can check for this situation.
551 	return result;
552 }
553 
554 
555 // _user_supports_moving_partition
556 bool
557 _user_supports_moving_partition(partition_id partitionID, int32 changeCounter,
558 	partition_id *_unmovable, partition_id *_needUnmounting, size_t bufferSize)
559 {
560 	if ((!_unmovable || !_needUnmounting) && bufferSize > 0)
561 		return false;
562 	partition_id *unmovable = NULL;
563 	partition_id *needUnmounting = NULL;
564 	if (bufferSize > 0) {
565 		unmovable = static_cast<partition_id*>(malloc(bufferSize));
566 		needUnmounting = static_cast<partition_id*>(malloc(bufferSize));
567 		if (unmovable && needUnmounting) {
568 			user_memcpy(unmovable, _unmovable, bufferSize);
569 			user_memcpy(needUnmounting, _needUnmounting, bufferSize);
570 		} else {
571 			free(unmovable);
572 			free(needUnmounting);
573 			return false;
574 		}
575 	}
576 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
577 	// get the partition
578 	KPartition *partition = manager->ReadLockPartition(partitionID);
579 	bool result = partition;
580 	if (result) {
581 		PartitionRegistrar registrar1(partition, true);
582 		PartitionRegistrar registrar2(partition->Device(), true);
583 		DeviceReadLocker locker(partition->Device(), true);
584 		result = check_shadow_partition(partition, changeCounter)
585 			&& partition->Parent();
586 		if (result) {
587 			result = !partition->Parent()->IsBusy()
588 				&& !partition->Parent()->IsDescendantBusy();
589 		}
590 		if (result) {
591 			// get the parent disk system
592 			KDiskSystem *parentDiskSystem = partition->Parent()->DiskSystem();
593 			result = parentDiskSystem;
594 			if (result) {
595 				result = parentDiskSystem->SupportsChildOperations(partition,
596 					B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD);
597 			}
598 
599 			if (result) {
600 				// check the movability of the descendants' contents
601 				size_t unmovableSize = bufferSize;
602 				size_t needUnmountingSize = bufferSize;
603 				result = get_unmovable_descendants(partition, unmovable,
604 					unmovableSize, needUnmounting, needUnmountingSize);
605 			}
606 		}
607 	}
608 	if (result && bufferSize > 0) {
609 		user_memcpy(_unmovable, unmovable, bufferSize);
610 		user_memcpy(_needUnmounting, needUnmounting, bufferSize);
611 	}
612 	free(unmovable);
613 	free(needUnmounting);
614 	return result;
615 }
616 
617 
618 // _user_supports_setting_partition_name
619 bool
620 _user_supports_setting_partition_name(partition_id partitionID,
621 	int32 changeCounter)
622 {
623 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
624 	// get the partition
625 	KPartition *partition = manager->ReadLockPartition(partitionID);
626 	if (!partition)
627 		return false;
628 	PartitionRegistrar registrar1(partition, true);
629 	PartitionRegistrar registrar2(partition->Device(), true);
630 	DeviceReadLocker locker(partition->Device(), true);
631 	if (!check_shadow_partition(partition, changeCounter)
632 		|| !partition->Parent()) {
633 		return false;
634 	}
635 	if (partition->Parent()->IsBusy()
636 		|| partition->Parent()->IsDescendantBusy()) {
637 		return false;
638 	}
639 
640 	// get the disk system
641 	KDiskSystem *diskSystem = partition->Parent()->DiskSystem();
642 	if (!diskSystem)
643 		return false;
644 
645 	// get the info
646 	return diskSystem->SupportsChildOperations(partition,
647 		B_DISK_SYSTEM_SUPPORTS_SETTING_NAME);
648 }
649 
650 // _user_supports_setting_partition_content_name
651 bool
652 _user_supports_setting_partition_content_name(partition_id partitionID,
653 	int32 changeCounter, bool *_whileMounted)
654 {
655 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
656 	// get the partition
657 	KPartition *partition = manager->ReadLockPartition(partitionID);
658 	if (!partition)
659 		return false;
660 	PartitionRegistrar registrar1(partition, true);
661 	PartitionRegistrar registrar2(partition->Device(), true);
662 	DeviceReadLocker locker(partition->Device(), true);
663 	if (!check_shadow_partition(partition, changeCounter))
664 		return false;
665 	if (partition->IsBusy() || partition->IsDescendantBusy())
666 		return false;
667 	// get the disk system
668 	KDiskSystem *diskSystem = partition->DiskSystem();
669 	if (!diskSystem)
670 		return false;
671 
672 	// get the info
673 	uint32 operations = diskSystem->GetSupportedOperations(partition,
674 		B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME
675 		| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED);
676 
677 	bool result = (operations & B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME);
678 	if (result && _whileMounted) {
679 		bool whileMounted = (operations
680 			& B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME_WHILE_MOUNTED);
681 		user_memcpy(_whileMounted, &whileMounted, sizeof(whileMounted));
682 	}
683 
684 	return result;
685 }
686 
687 
688 // _user_supports_setting_partition_type
689 bool
690 _user_supports_setting_partition_type(partition_id partitionID,
691 	int32 changeCounter)
692 {
693 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
694 	// get the partition
695 	KPartition *partition = manager->ReadLockPartition(partitionID);
696 	if (!partition)
697 		return false;
698 	PartitionRegistrar registrar1(partition, true);
699 	PartitionRegistrar registrar2(partition->Device(), true);
700 	DeviceReadLocker locker(partition->Device(), true);
701 	if (!check_shadow_partition(partition, changeCounter)
702 		|| !partition->Parent()) {
703 		return false;
704 	}
705 	if (partition->Parent()->IsBusy()
706 		|| partition->Parent()->IsDescendantBusy()) {
707 		return false;
708 	}
709 	// get the disk system
710 	KDiskSystem *diskSystem = partition->Parent()->DiskSystem();
711 	if (!diskSystem)
712 		return false;
713 	// get the info
714 	return diskSystem->SupportsChildOperations(partition,
715 		B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE);
716 }
717 
718 
719 // _user_supports_setting_partition_parameters
720 bool
721 _user_supports_setting_partition_parameters(partition_id partitionID,
722 	int32 changeCounter)
723 {
724 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
725 	// get the partition
726 	KPartition *partition = manager->ReadLockPartition(partitionID);
727 	if (!partition)
728 		return false;
729 	PartitionRegistrar registrar1(partition, true);
730 	PartitionRegistrar registrar2(partition->Device(), true);
731 	DeviceReadLocker locker(partition->Device(), true);
732 	if (!check_shadow_partition(partition, changeCounter)
733 		|| !partition->Parent()) {
734 		return false;
735 	}
736 	if (partition->Parent()->IsBusy()
737 		|| partition->Parent()->IsDescendantBusy()) {
738 		return false;
739 	}
740 	// get the disk system
741 	KDiskSystem *diskSystem = partition->Parent()->DiskSystem();
742 	if (!diskSystem)
743 		return false;
744 	// get the info
745 	return diskSystem->SupportsChildOperations(partition,
746 		B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS);
747 }
748 
749 
750 // _user_supports_setting_partition_content_parameters
751 bool
752 _user_supports_setting_partition_content_parameters(partition_id partitionID,
753 	int32 changeCounter, bool *_whileMounted)
754 {
755 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
756 	// get the partition
757 	KPartition *partition = manager->ReadLockPartition(partitionID);
758 	if (!partition)
759 		return false;
760 	PartitionRegistrar registrar1(partition, true);
761 	PartitionRegistrar registrar2(partition->Device(), true);
762 	DeviceReadLocker locker(partition->Device(), true);
763 	if (!check_shadow_partition(partition, changeCounter))
764 		return false;
765 	if (partition->IsBusy() || partition->IsDescendantBusy())
766 		return false;
767 	// get the disk system
768 	KDiskSystem *diskSystem = partition->DiskSystem();
769 	if (!diskSystem)
770 		return false;
771 	// get the info
772 	uint32 operations = diskSystem->GetSupportedOperations(partition,
773 		B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS
774 		| B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED);
775 	bool result = (operations
776 		& B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS);
777 	if (result && _whileMounted) {
778 		bool whileMounted = (operations
779 			& B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS_WHILE_MOUNTED);
780 		user_memcpy(_whileMounted, &whileMounted, sizeof(whileMounted));
781 	}
782 	return result;
783 }
784 
785 
786 // _user_supports_initializing_partition
787 bool
788 _user_supports_initializing_partition(partition_id partitionID,
789 	int32 changeCounter, const char *_diskSystemName)
790 {
791 	if (!_diskSystemName)
792 		return false;
793 	char diskSystemName[B_DISK_SYSTEM_NAME_LENGTH];
794 	status_t error = ddm_strlcpy(diskSystemName, _diskSystemName, B_DISK_SYSTEM_NAME_LENGTH);
795 	if (error)
796 		return error;
797 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
798 
799 	// get the partition
800 	KPartition *partition = manager->ReadLockPartition(partitionID);
801 	if (!partition)
802 		return false;
803 	PartitionRegistrar registrar1(partition, true);
804 	PartitionRegistrar registrar2(partition->Device(), true);
805 	DeviceReadLocker locker(partition->Device(), true);
806 	if (!check_shadow_partition(partition, changeCounter))
807 		return false;
808 	if (partition->IsBusy() || partition->IsDescendantBusy())
809 		return false;
810 
811 	// get the disk system
812 	KDiskSystem *diskSystem = manager->LoadDiskSystem(diskSystemName);
813 	if (!diskSystem)
814 		return false;
815 	DiskSystemLoader loader(diskSystem, true);
816 
817 	// get the info
818 	if (!diskSystem->SupportsOperations(partition,
819 		B_DISK_SYSTEM_SUPPORTS_INITIALIZING)) {
820 		return false;
821 	}
822 
823 	// get the parent partition's disk system
824 	KPartition* parentPartition = partition->Parent();
825 	if (!parentPartition)
826 		return true;
827 
828 	KDiskSystem* parentDiskSystem = parentPartition->DiskSystem();
829 	if (!parentDiskSystem)
830 		return false;	// something's fishy!
831 
832 	// ask the parent disk system
833 	return parentDiskSystem->SupportsInitializingChild(partition,
834 		diskSystemName);
835 }
836 
837 
838 // _user_supports_creating_child_partition
839 bool
840 _user_supports_creating_child_partition(partition_id partitionID,
841 	int32 changeCounter)
842 {
843 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
844 	// get the partition
845 	KPartition *partition = manager->ReadLockPartition(partitionID);
846 	if (!partition)
847 		return false;
848 	PartitionRegistrar registrar1(partition, true);
849 	PartitionRegistrar registrar2(partition->Device(), true);
850 	DeviceReadLocker locker(partition->Device(), true);
851 	if (!check_shadow_partition(partition, changeCounter))
852 		return false;
853 	if (partition->IsBusy() || partition->IsDescendantBusy())
854 		return false;
855 	// get the disk system
856 	KDiskSystem *diskSystem = partition->DiskSystem();
857 	if (!diskSystem)
858 		return false;
859 	// get the info
860 	return diskSystem->SupportsOperations(partition,
861 		B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD);
862 }
863 
864 
865 // _user_supports_deleting_child_partition
866 bool
867 _user_supports_deleting_child_partition(partition_id partitionID,
868 	int32 changeCounter)
869 {
870 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
871 	// get the partition
872 	KPartition *partition = manager->ReadLockPartition(partitionID);
873 	if (!partition)
874 		return false;
875 	PartitionRegistrar registrar1(partition, true);
876 	PartitionRegistrar registrar2(partition->Device(), true);
877 	DeviceReadLocker locker(partition->Device(), true);
878 	return (validate_delete_child_partition(partition, changeCounter) == B_OK);
879 }
880 
881 
882 // _user_is_sub_disk_system_for
883 bool
884 _user_is_sub_disk_system_for(disk_system_id diskSystemID,
885 	partition_id partitionID, int32 changeCounter)
886 {
887 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
888 	// get the partition
889 	KPartition *partition = manager->ReadLockPartition(partitionID);
890 	if (!partition)
891 		return false;
892 	PartitionRegistrar registrar1(partition, true);
893 	PartitionRegistrar registrar2(partition->Device(), true);
894 	DeviceReadLocker locker(partition->Device(), true);
895 	if (!check_shadow_partition(partition, changeCounter))
896 		return false;
897 	// get the disk system
898 	KDiskSystem *diskSystem = partition->DiskSystem();
899 	if (!diskSystem || diskSystem->ID() != diskSystemID)
900 		return false;
901 	// get the info
902 	return diskSystem->IsSubSystemFor(partition);
903 }
904 
905 
906 // _user_validate_resize_partition
907 status_t
908 _user_validate_resize_partition(partition_id partitionID, int32 changeCounter,
909 	off_t *_size)
910 {
911 	if (!_size)
912 		return B_BAD_VALUE;
913 	off_t size;
914 	user_memcpy(&size, _size, sizeof(size));
915 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
916 	// get the partition
917 	KPartition *partition = manager->ReadLockPartition(partitionID);
918 	if (!partition)
919 		return B_ENTRY_NOT_FOUND;
920 	PartitionRegistrar registrar1(partition, true);
921 	PartitionRegistrar registrar2(partition->Device(), true);
922 	DeviceReadLocker locker(partition->Device(), true);
923 	off_t contentSize = 0;
924 	bool result = validate_resize_partition(partition, changeCounter, &size,
925 		&contentSize);
926 	if (result)
927 		user_memcpy(_size, &size, sizeof(size));
928 	return result;
929 }
930 
931 
932 // _user_validate_move_partition
933 status_t
934 _user_validate_move_partition(partition_id partitionID, int32 changeCounter,
935 	off_t *_newOffset)
936 {
937 	if (!_newOffset)
938 		return B_BAD_VALUE;
939 	off_t newOffset;
940 	user_memcpy(&newOffset, _newOffset, sizeof(newOffset));
941 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
942 	// get the partition
943 	KPartition *partition = manager->ReadLockPartition(partitionID);
944 	if (!partition)
945 		return B_ENTRY_NOT_FOUND;
946 	PartitionRegistrar registrar1(partition, true);
947 	PartitionRegistrar registrar2(partition->Device(), true);
948 	DeviceReadLocker locker(partition->Device(), true);
949 	status_t result = validate_move_partition(partition, changeCounter,
950 		&newOffset);
951 	if (result)
952 		user_memcpy(_newOffset, &newOffset, sizeof(newOffset));
953 	return result;
954 }
955 
956 
957 // _user_validate_set_partition_name
958 status_t
959 _user_validate_set_partition_name(partition_id partitionID,
960 	int32 changeCounter, char *_name)
961 {
962 	if (!_name)
963 		return B_BAD_VALUE;
964 	char name[B_DISK_DEVICE_NAME_LENGTH];
965 	status_t error = ddm_strlcpy(name, _name, B_DISK_DEVICE_NAME_LENGTH, true);
966 	if (error)
967 		return error;
968 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
969 	// get the partition
970 	KPartition *partition = manager->ReadLockPartition(partitionID);
971 	if (!partition)
972 		return B_ENTRY_NOT_FOUND;
973 	PartitionRegistrar registrar1(partition, true);
974 	PartitionRegistrar registrar2(partition->Device(), true);
975 	DeviceReadLocker locker(partition->Device(), true);
976 	error = validate_set_partition_name(partition, changeCounter, name);
977 	if (!error)
978 		error = ddm_strlcpy(_name, name, B_DISK_DEVICE_NAME_LENGTH);
979 	return error;
980 }
981 
982 
983 // _user_validate_set_partition_content_name
984 status_t
985 _user_validate_set_partition_content_name(partition_id partitionID,
986 										  int32 changeCounter, char *_name)
987 {
988 	if (!_name)
989 		return B_BAD_VALUE;
990 	char name[B_DISK_DEVICE_NAME_LENGTH];
991 	status_t error = ddm_strlcpy(name, _name, B_DISK_DEVICE_NAME_LENGTH, true);
992 	if (error)
993 		return error;
994 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
995 	// get the partition
996 	KPartition *partition = manager->ReadLockPartition(partitionID);
997 	if (!partition)
998 		return B_ENTRY_NOT_FOUND;
999 	PartitionRegistrar registrar1(partition, true);
1000 	PartitionRegistrar registrar2(partition->Device(), true);
1001 	DeviceReadLocker locker(partition->Device(), true);
1002 	error = validate_set_partition_content_name(partition, changeCounter, name);
1003 	if (!error)
1004 		error = ddm_strlcpy(_name, name, B_DISK_DEVICE_NAME_LENGTH);
1005 	return error;
1006 }
1007 
1008 
1009 // _user_validate_set_partition_type
1010 status_t
1011 _user_validate_set_partition_type(partition_id partitionID,
1012 	int32 changeCounter, const char *_type)
1013 {
1014 	if (!_type)
1015 		return B_BAD_VALUE;
1016 	char type[B_DISK_DEVICE_TYPE_LENGTH];
1017 	status_t error = ddm_strlcpy(type, _type, B_DISK_DEVICE_TYPE_LENGTH);
1018 	if (error)
1019 		return error;
1020 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1021 	// get the partition
1022 	KPartition *partition = manager->ReadLockPartition(partitionID);
1023 	if (!partition)
1024 		return B_ENTRY_NOT_FOUND;
1025 	PartitionRegistrar registrar1(partition, true);
1026 	PartitionRegistrar registrar2(partition->Device(), true);
1027 	DeviceReadLocker locker(partition->Device(), true);
1028 	return validate_set_partition_type(partition, changeCounter, type);
1029 }
1030 
1031 
1032 // _user_validate_initialize_partition
1033 status_t
1034 _user_validate_initialize_partition(partition_id partitionID,
1035 	int32 changeCounter, const char *_diskSystemName, char *_name,
1036 	const char *_parameters, size_t parametersSize)
1037 {
1038 	if (!_diskSystemName || parametersSize > B_DISK_DEVICE_MAX_PARAMETER_SIZE)
1039 		return B_BAD_VALUE;
1040 
1041 	// copy disk system name
1042 	char diskSystemName[B_DISK_SYSTEM_NAME_LENGTH];
1043 	status_t error = ddm_strlcpy(diskSystemName, _diskSystemName,
1044 		B_DISK_SYSTEM_NAME_LENGTH);
1045 
1046 	// copy name
1047 	char name[B_DISK_DEVICE_NAME_LENGTH];
1048 	if (!error && _name)
1049 		error = ddm_strlcpy(name, _name, B_DISK_DEVICE_NAME_LENGTH, true);
1050 
1051 	if (error != B_OK)
1052 		return error;
1053 
1054 	// copy parameters
1055 	char *parameters = NULL;
1056 	MemoryDeleter parameterDeleter;
1057 	if (_parameters) {
1058 		parameters = static_cast<char*>(malloc(parametersSize));
1059 		if (!parameters)
1060 			return B_NO_MEMORY;
1061 		parameterDeleter.SetTo(parameters);
1062 
1063 		if (user_memcpy(parameters, _parameters, parametersSize) != B_OK)
1064 			return B_BAD_ADDRESS;
1065 	}
1066 
1067 	// get the partition
1068 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1069 	KPartition *partition = manager->ReadLockPartition(partitionID);
1070 	if (!partition)
1071 		return B_ENTRY_NOT_FOUND;
1072 
1073 	// validate
1074 	PartitionRegistrar registrar1(partition, true);
1075 	PartitionRegistrar registrar2(partition->Device(), true);
1076 	DeviceReadLocker locker(partition->Device(), true);
1077 	error = validate_initialize_partition(partition, changeCounter,
1078 		diskSystemName, _name ? name : NULL, parameters);
1079 
1080 	// copy back the modified name
1081 	if (!error && _name)
1082 		error = ddm_strlcpy(_name, name, B_DISK_DEVICE_NAME_LENGTH);
1083 
1084 	return error;
1085 }
1086 
1087 
1088 // _user_validate_create_child_partition
1089 status_t
1090 _user_validate_create_child_partition(partition_id partitionID,
1091 	int32 changeCounter, off_t *_offset, off_t *_size, const char *_type,
1092 	const char *_parameters, size_t parametersSize)
1093 {
1094 	if (!_offset || !_size || !_type
1095 	    || parametersSize > B_DISK_DEVICE_MAX_PARAMETER_SIZE) {
1096 		return B_BAD_VALUE;
1097 	}
1098 	off_t offset;
1099 	off_t size;
1100 	char type[B_DISK_DEVICE_TYPE_LENGTH];
1101 	char *parameters = NULL;
1102 	user_memcpy(&offset, _offset, sizeof(offset));
1103 	user_memcpy(&size, _size, sizeof(size));
1104 	status_t error = ddm_strlcpy(type, _type, B_DISK_DEVICE_TYPE_LENGTH);
1105 	if (error)
1106 		return error;
1107 	if (_parameters) {
1108 		parameters = static_cast<char*>(malloc(parametersSize));
1109 		if (parameters)
1110 			user_memcpy(parameters, _parameters, parametersSize);
1111 		else
1112 			return B_NO_MEMORY;
1113 	}
1114 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1115 	// get the partition
1116 	KPartition *partition = manager->ReadLockPartition(partitionID);
1117 	error = partition ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
1118 	if (!error) {
1119 		PartitionRegistrar registrar1(partition, true);
1120 		PartitionRegistrar registrar2(partition->Device(), true);
1121 		DeviceReadLocker locker(partition->Device(), true);
1122 		error = validate_create_child_partition(partition, changeCounter,
1123 			&offset, &size, type, parameters);
1124 	}
1125 	if (!error) {
1126 		user_memcpy(_offset, &offset, sizeof(offset));
1127 		user_memcpy(_size, &size, sizeof(size));
1128 	}
1129 	free(parameters);
1130 	return error;
1131 }
1132 
1133 
1134 // _user_get_next_supported_partition_type
1135 status_t
1136 _user_get_next_supported_partition_type(partition_id partitionID,
1137 	int32 changeCounter, int32 *_cookie, char *_type)
1138 {
1139 	if (!_cookie || !_type)
1140 		return B_BAD_VALUE;
1141 	int32 cookie;
1142 	user_memcpy(&cookie, _cookie, sizeof(cookie));
1143 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1144 	// get the partition
1145 	KPartition *partition = manager->ReadLockPartition(partitionID);
1146 	status_t error = partition ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
1147 	if (!error) {
1148 		PartitionRegistrar registrar1(partition, true);
1149 		PartitionRegistrar registrar2(partition->Device(), true);
1150 		DeviceReadLocker locker(partition->Device(), true);
1151 		error = check_shadow_partition(partition, changeCounter)
1152 			? B_OK : B_BAD_VALUE;
1153 		if (!error) {
1154 			// get the disk system
1155 			KDiskSystem *diskSystem = partition->DiskSystem();
1156 			error = diskSystem ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
1157 			if (!error) {
1158 				// get the info
1159 				char type[B_DISK_DEVICE_TYPE_LENGTH];
1160 				error = diskSystem->GetNextSupportedType(partition, &cookie,
1161 					type);
1162 				if (!error)
1163 					error = ddm_strlcpy(_type, type, B_DISK_DEVICE_TYPE_LENGTH);
1164 			}
1165 		}
1166 	}
1167 	if (!error)
1168 		user_memcpy(_cookie, &cookie, sizeof(cookie));
1169 	return error;
1170 }
1171 
1172 
1173 // _user_get_partition_type_for_content_type
1174 status_t
1175 _user_get_partition_type_for_content_type(disk_system_id diskSystemID,
1176 	const char *_contentType, char *_type)
1177 {
1178 	if (!_contentType || !_type)
1179 		return B_BAD_VALUE;
1180 	char contentType[B_DISK_DEVICE_TYPE_LENGTH];
1181 	status_t error = ddm_strlcpy(contentType, _contentType,
1182 			B_DISK_DEVICE_TYPE_LENGTH);
1183 	if (error)
1184 		return error;
1185 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1186 	// get the disk system
1187 	KDiskSystem *diskSystem = manager->LoadDiskSystem(diskSystemID);
1188 	if (!diskSystem)
1189 		return false;
1190 	DiskSystemLoader loader(diskSystem, true);
1191 	// get the info
1192 	char type[B_DISK_DEVICE_TYPE_LENGTH];
1193 	if (diskSystem->GetTypeForContentType(contentType, type))
1194 		return ddm_strlcpy(_type, type, B_DISK_DEVICE_TYPE_LENGTH);
1195 	return B_ERROR;
1196 }
1197 
1198 
1199 // _user_prepare_disk_device_modifications
1200 status_t
1201 _user_prepare_disk_device_modifications(partition_id deviceID)
1202 {
1203 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1204 	// get the device
1205 	if (KDiskDevice *device = manager->RegisterDevice(deviceID, true)) {
1206 		PartitionRegistrar _(device, true);
1207 		if (DeviceWriteLocker locker = device) {
1208 			if (device->ShadowOwner() >= 0)
1209 				return B_BUSY;
1210 			// create shadow device
1211 			return device->CreateShadowDevice(get_current_team());
1212 		}
1213 	}
1214 	return B_ENTRY_NOT_FOUND;
1215 }
1216 
1217 // _user_commit_disk_device_modifications
1218 status_t
1219 _user_commit_disk_device_modifications(partition_id deviceID, port_id port,
1220 	int32 token, bool completeProgress)
1221 {
1222 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1223 	// get the device
1224 	if (KDiskDevice *device = manager->RegisterDevice(deviceID, true)) {
1225 		PartitionRegistrar _(device, true);
1226 		if (DeviceWriteLocker locker = device) {
1227 			if (device->ShadowOwner() != get_current_team())
1228 				return B_BAD_VALUE;
1229 			// generate the jobs
1230 			KDiskDeviceJobGenerator generator(manager->JobFactory(), device);
1231 			status_t error = generator.GenerateJobs();
1232 			if (error != B_OK)
1233 				return error;
1234 			// add the jobs to the manager
1235 			if (ManagerLocker locker2 = manager) {
1236 				error = manager->AddJobQueue(generator.JobQueue());
1237 				if (error == B_OK)
1238 					generator.DetachJobQueue();
1239 				else
1240 					return error;
1241 			} else
1242 				return B_ERROR;
1243 			// TODO: notification stuff
1244 			return device->DeleteShadowDevice();
1245 		}
1246 	}
1247 	return B_ENTRY_NOT_FOUND;
1248 }
1249 
1250 
1251 // _user_cancel_disk_device_modifications
1252 status_t
1253 _user_cancel_disk_device_modifications(partition_id deviceID)
1254 {
1255 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1256 	// get the device
1257 	if (KDiskDevice *device = manager->RegisterDevice(deviceID, true)) {
1258 		PartitionRegistrar _(device, true);
1259 		if (DeviceWriteLocker locker = device) {
1260 			if (device->ShadowOwner() != get_current_team())
1261 				return B_BAD_VALUE;
1262 			// delete shadow device
1263 			return device->DeleteShadowDevice();
1264 		}
1265 	}
1266 	return B_ENTRY_NOT_FOUND;
1267 }
1268 
1269 
1270 // _user_is_disk_device_modified
1271 bool
1272 _user_is_disk_device_modified(partition_id deviceID)
1273 {
1274 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1275 	// get the device
1276 	if (KDiskDevice *device = manager->RegisterDevice(deviceID, true)) {
1277 		PartitionRegistrar _(device, true);
1278 		if (DeviceReadLocker locker = device) {
1279 			// check whether there's a shadow device and whether it's changed
1280 			return (device->ShadowOwner() == get_current_team()
1281 				&& device->ShadowPartition()
1282 				&& device->ShadowPartition()->ChangeFlags() != 0);
1283 		}
1284 	}
1285 	return B_ENTRY_NOT_FOUND;
1286 }
1287 
1288 
1289 // _user_defragment_partition
1290 status_t
1291 _user_defragment_partition(partition_id partitionID, int32 changeCounter)
1292 {
1293 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1294 	// get the partition
1295 	KPartition *partition = manager->WriteLockPartition(partitionID);
1296 	if (!partition)
1297 		return B_ENTRY_NOT_FOUND;
1298 	PartitionRegistrar registrar1(partition, true);
1299 	PartitionRegistrar registrar2(partition->Device(), true);
1300 	DeviceWriteLocker locker(partition->Device(), true);
1301 	// check whether the disk system supports defragmenting
1302 	status_t error = validate_defragment_partition(partition, changeCounter);
1303 	if (error != B_OK)
1304 		return error;
1305 	// set the defragmenting flag
1306 	partition->Changed(B_PARTITION_CHANGED_DEFRAGMENTATION);
1307 	return B_OK;
1308 }
1309 
1310 
1311 // _user_repair_partition
1312 status_t
1313 _user_repair_partition(partition_id partitionID, int32 changeCounter,
1314 	bool checkOnly)
1315 {
1316 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1317 	// get the partition
1318 	KPartition *partition = manager->WriteLockPartition(partitionID);
1319 	if (!partition)
1320 		return B_ENTRY_NOT_FOUND;
1321 	PartitionRegistrar registrar1(partition, true);
1322 	PartitionRegistrar registrar2(partition->Device(), true);
1323 	DeviceWriteLocker locker(partition->Device(), true);
1324 	// check whether the disk system supports defragmenting
1325 	status_t error = validate_repair_partition(partition, changeCounter,
1326 		checkOnly);
1327 	if (error != B_OK)
1328 		return error;
1329 	// set the respective flag
1330 	if (checkOnly)
1331 		partition->Changed(B_PARTITION_CHANGED_CHECK);
1332 	else
1333 		partition->Changed(B_PARTITION_CHANGED_REPAIR);
1334 	return B_OK;
1335 }
1336 
1337 
1338 // _user_resize_partition
1339 status_t
1340 _user_resize_partition(partition_id partitionID, int32 changeCounter,
1341 	off_t size)
1342 {
1343 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1344 	// get the partition
1345 	KPartition *partition = manager->WriteLockPartition(partitionID);
1346 	if (!partition)
1347 		return B_ENTRY_NOT_FOUND;
1348 	PartitionRegistrar registrar1(partition, true);
1349 	PartitionRegistrar registrar2(partition->Device(), true);
1350 	DeviceWriteLocker locker(partition->Device(), true);
1351 	// check the size
1352 	if (size == partition->Size())
1353 		return B_OK;
1354 	off_t proposedSize = size;
1355 	off_t contentSize = 0;
1356 	status_t error = validate_resize_partition(partition, changeCounter,
1357 		&proposedSize, &contentSize);
1358 	if (error != B_OK)
1359 		return error;
1360 	if (proposedSize != size)
1361 		return B_BAD_VALUE;
1362 	// new size is fine -- resize the thing
1363 	partition->SetSize(size);
1364 	partition->Changed(B_PARTITION_CHANGED_SIZE);
1365 	// implicit partitioning system changes
1366 	error = partition->Parent()->DiskSystem()->ShadowPartitionChanged(
1367 		partition->Parent(), partition, B_PARTITION_RESIZE_CHILD);
1368 	if (error != B_OK)
1369 		return error;
1370 	// implicit content disk system changes
1371 	if (partition->DiskSystem()) {
1372 		error = partition->DiskSystem()->ShadowPartitionChanged(
1373 			partition, NULL, B_PARTITION_RESIZE);
1374 	}
1375 	return error;
1376 }
1377 
1378 
1379 // _user_move_partition
1380 status_t
1381 _user_move_partition(partition_id partitionID, int32 changeCounter,
1382 	off_t newOffset)
1383 {
1384 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1385 	// get the partition
1386 	KPartition *partition = manager->WriteLockPartition(partitionID);
1387 	if (!partition)
1388 		return B_ENTRY_NOT_FOUND;
1389 	PartitionRegistrar registrar1(partition, true);
1390 	PartitionRegistrar registrar2(partition->Device(), true);
1391 	DeviceWriteLocker locker(partition->Device(), true);
1392 	// check the new offset
1393 	if (newOffset == partition->Offset())
1394 		return B_OK;
1395 	off_t proposedOffset = newOffset;
1396 	status_t error = validate_move_partition(partition, changeCounter,
1397 		&proposedOffset, true);
1398 	if (error != B_OK)
1399 		return error;
1400 	if (proposedOffset != newOffset)
1401 		return B_BAD_VALUE;
1402 	// new offset is fine -- move the thing
1403 	off_t moveBy = newOffset - partition->Offset();
1404 	move_descendants(partition, moveBy);
1405 	partition->Changed(B_PARTITION_CHANGED_OFFSET);
1406 	// implicit partitioning system changes
1407 	error = partition->Parent()->DiskSystem()->ShadowPartitionChanged(
1408 		partition->Parent(), partition, B_PARTITION_MOVE_CHILD);
1409 	if (error != B_OK)
1410 		return error;
1411 	// implicit descendants' content disk system changes
1412 	return move_descendants_contents(partition);
1413 }
1414 
1415 
1416 // _user_set_partition_name
1417 status_t
1418 _user_set_partition_name(partition_id partitionID, int32 changeCounter,
1419 	const char *_name)
1420 {
1421 	if (!_name)
1422 		return B_BAD_VALUE;
1423 	char name[B_DISK_DEVICE_NAME_LENGTH];
1424 	status_t error = ddm_strlcpy(name, _name, B_DISK_DEVICE_NAME_LENGTH);
1425 	if (error)
1426 		return error;
1427 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1428 	// get the partition
1429 	KPartition *partition = manager->WriteLockPartition(partitionID);
1430 	if (!partition)
1431 		return B_ENTRY_NOT_FOUND;
1432 	PartitionRegistrar registrar1(partition, true);
1433 	PartitionRegistrar registrar2(partition->Device(), true);
1434 	DeviceWriteLocker locker(partition->Device(), true);
1435 	// check name
1436 	char proposedName[B_DISK_DEVICE_NAME_LENGTH];
1437 	strcpy(proposedName, name);
1438 	error = validate_set_partition_name(partition, changeCounter, proposedName);
1439 	if (error != B_OK)
1440 		return error;
1441 	if (strcmp(name, proposedName))
1442 		return B_BAD_VALUE;
1443 	// set name
1444 	error = partition->SetName(name);
1445 	if (error != B_OK)
1446 		return error;
1447 	partition->Changed(B_PARTITION_CHANGED_NAME);
1448 	// implicit partitioning system changes
1449 	return partition->Parent()->DiskSystem()->ShadowPartitionChanged(
1450 		partition->Parent(), partition, B_PARTITION_SET_NAME);
1451 }
1452 
1453 
1454 // _user_set_partition_content_name
1455 status_t
1456 _user_set_partition_content_name(partition_id partitionID, int32 changeCounter,
1457 	const char *_name)
1458 {
1459 	if (!_name)
1460 		return B_BAD_VALUE;
1461 	char name[B_DISK_DEVICE_NAME_LENGTH];
1462 	status_t error = ddm_strlcpy(name, _name, B_DISK_DEVICE_NAME_LENGTH);
1463 	if (error)
1464 		return error;
1465 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1466 	// get the partition
1467 	KPartition *partition = manager->WriteLockPartition(partitionID);
1468 	if (!partition)
1469 		return B_ENTRY_NOT_FOUND;
1470 	PartitionRegistrar registrar1(partition, true);
1471 	PartitionRegistrar registrar2(partition->Device(), true);
1472 	DeviceWriteLocker locker(partition->Device(), true);
1473 	// check name
1474 	char proposedName[B_DISK_DEVICE_NAME_LENGTH];
1475 	strcpy(proposedName, name);
1476 	error = validate_set_partition_content_name(partition,
1477 		changeCounter, proposedName);
1478 	if (error != B_OK)
1479 		return error;
1480 	if (strcmp(name, proposedName))
1481 		return B_BAD_VALUE;
1482 	// set name
1483 	error = partition->SetContentName(name);
1484 	if (error != B_OK)
1485 		return error;
1486 	partition->Changed(B_PARTITION_CHANGED_CONTENT_NAME);
1487 	// implicit content disk system changes
1488 	return partition->DiskSystem()->ShadowPartitionChanged(
1489 		partition, NULL, B_PARTITION_SET_CONTENT_NAME);
1490 }
1491 
1492 
1493 // _user_set_partition_type
1494 status_t
1495 _user_set_partition_type(partition_id partitionID, int32 changeCounter,
1496 	const char *_type)
1497 {
1498 	if (!_type)
1499 		return B_BAD_VALUE;
1500 	char type[B_DISK_DEVICE_TYPE_LENGTH];
1501 	status_t error = ddm_strlcpy(type, _type, B_DISK_DEVICE_TYPE_LENGTH);
1502 	if (error)
1503 		return error;
1504 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1505 	// get the partition
1506 	KPartition *partition = manager->WriteLockPartition(partitionID);
1507 	if (!partition)
1508 		return B_ENTRY_NOT_FOUND;
1509 	PartitionRegistrar registrar1(partition, true);
1510 	PartitionRegistrar registrar2(partition->Device(), true);
1511 	DeviceWriteLocker locker(partition->Device(), true);
1512 	// check type
1513 	error = validate_set_partition_type(partition, changeCounter, type);
1514 	if (error != B_OK)
1515 		return error;
1516 	// set type
1517 	error = partition->SetType(type);
1518 	if (error != B_OK)
1519 		return error;
1520 	partition->Changed(B_PARTITION_CHANGED_TYPE);
1521 	// implicit partitioning system changes
1522 	return partition->Parent()->DiskSystem()->ShadowPartitionChanged(
1523 		partition->Parent(), partition, B_PARTITION_SET_TYPE);
1524 }
1525 
1526 
1527 // _user_set_partition_parameters
1528 status_t
1529 _user_set_partition_parameters(partition_id partitionID, int32 changeCounter,
1530 	const char *_parameters, size_t parametersSize)
1531 {
1532 	if (!_parameters || parametersSize > B_DISK_DEVICE_MAX_PARAMETER_SIZE)
1533 		return B_BAD_VALUE;
1534 	char *parameters = NULL;
1535 	if (_parameters) {
1536 		parameters = static_cast<char*>(malloc(parametersSize));
1537 		if (parameters)
1538 			user_memcpy(parameters, _parameters, parametersSize);
1539 		else
1540 			return B_NO_MEMORY;
1541 	}
1542 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1543 	// get the partition
1544 	KPartition *partition = manager->WriteLockPartition(partitionID);
1545 	status_t error = partition ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
1546 	if (!error) {
1547 		PartitionRegistrar registrar1(partition, true);
1548 		PartitionRegistrar registrar2(partition->Device(), true);
1549 		DeviceWriteLocker locker(partition->Device(), true);
1550 		// check parameters
1551 		error = validate_set_partition_parameters(partition,
1552 			changeCounter, parameters);
1553 		if (!error) {
1554 			// set type
1555 			error = partition->SetParameters(parameters);
1556 			if (!error) {
1557 				partition->Changed(B_PARTITION_CHANGED_PARAMETERS);
1558 				// implicit partitioning system changes
1559 				error = partition->Parent()->DiskSystem()
1560 					->ShadowPartitionChanged(partition->Parent(), partition,
1561 						B_PARTITION_SET_PARAMETERS);
1562 			}
1563 		}
1564 	}
1565 	free(parameters);
1566 	return error;
1567 }
1568 
1569 
1570 // _user_set_partition_content_parameters
1571 status_t
1572 _user_set_partition_content_parameters(partition_id partitionID,
1573 	int32 changeCounter, const char *_parameters, size_t parametersSize)
1574 {
1575 	if (!_parameters || parametersSize > B_DISK_DEVICE_MAX_PARAMETER_SIZE)
1576 		return B_BAD_VALUE;
1577 	char *parameters = NULL;
1578 	if (_parameters) {
1579 		parameters = static_cast<char*>(malloc(parametersSize));
1580 		if (parameters)
1581 			user_memcpy(parameters, _parameters, parametersSize);
1582 		else
1583 			return B_NO_MEMORY;
1584 	}
1585 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1586 	// get the partition
1587 	KPartition *partition = manager->WriteLockPartition(partitionID);
1588 	status_t error = partition ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
1589 	if (!error) {
1590 		PartitionRegistrar registrar1(partition, true);
1591 		PartitionRegistrar registrar2(partition->Device(), true);
1592 		DeviceWriteLocker locker(partition->Device(), true);
1593 		// check parameters
1594 		error = validate_set_partition_content_parameters(partition,
1595 			changeCounter, parameters);
1596 		if (!error) {
1597 			// set name
1598 			error = partition->SetContentParameters(parameters);
1599 			if (!error) {
1600 				partition->Changed(B_PARTITION_CHANGED_CONTENT_PARAMETERS);
1601 				// implicit content disk system changes
1602 				error = partition->DiskSystem()->ShadowPartitionChanged(
1603 					partition, NULL, B_PARTITION_SET_CONTENT_PARAMETERS);
1604 			}
1605 		}
1606 	}
1607 	free(partition);
1608 	return error;
1609 }
1610 
1611 
1612 // _user_initialize_partition
1613 status_t
1614 _user_initialize_partition(partition_id partitionID, int32 changeCounter,
1615 	const char *_diskSystemName, const char *_name, const char *_parameters,
1616 	size_t parametersSize)
1617 {
1618 	if (!_diskSystemName || parametersSize > B_DISK_DEVICE_MAX_PARAMETER_SIZE)
1619 		return B_BAD_VALUE;
1620 
1621 	// copy disk system name
1622 	char diskSystemName[B_DISK_SYSTEM_NAME_LENGTH];
1623 	status_t error = ddm_strlcpy(diskSystemName, _diskSystemName,
1624 		B_DISK_SYSTEM_NAME_LENGTH);
1625 
1626 	// copy name
1627 	char name[B_DISK_DEVICE_NAME_LENGTH];
1628 	if (!error && _name)
1629 		error = ddm_strlcpy(name, _name, B_DISK_DEVICE_NAME_LENGTH);
1630 
1631 	if (error)
1632 		return error;
1633 
1634 	// copy parameters
1635 	MemoryDeleter parameterDeleter;
1636 	char *parameters = NULL;
1637 	if (_parameters) {
1638 		parameters = static_cast<char*>(malloc(parametersSize));
1639 		if (!parameters)
1640 			return B_NO_MEMORY;
1641 		parameterDeleter.SetTo(parameters);
1642 
1643 		if (user_memcpy(parameters, _parameters, parametersSize) != B_OK)
1644 			return B_BAD_ADDRESS;
1645 	}
1646 
1647 	// get the partition
1648 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1649 	KPartition *partition = manager->WriteLockPartition(partitionID);
1650 	if (!partition)
1651 		return B_ENTRY_NOT_FOUND;
1652 
1653 	PartitionRegistrar registrar1(partition, true);
1654 	PartitionRegistrar registrar2(partition->Device(), true);
1655 	DeviceWriteLocker locker(partition->Device(), true);
1656 
1657 	// get the disk system
1658 	KDiskSystem *diskSystem = manager->LoadDiskSystem(diskSystemName);
1659 	if (!diskSystem)
1660 		return B_ENTRY_NOT_FOUND;
1661 	DiskSystemLoader loader(diskSystem, true);
1662 
1663 	// check parameters
1664 	char proposedName[B_DISK_DEVICE_NAME_LENGTH];
1665 	if (_name)
1666 		strcpy(proposedName, name);
1667 
1668 	error = validate_initialize_partition(partition, changeCounter,
1669 		diskSystemName, _name ? proposedName : NULL, parameters);
1670 	if (error != B_OK)
1671 		return error;
1672 	if (_name && strcmp(name, proposedName) != 0)
1673 		return B_BAD_VALUE;
1674 
1675 	// unitialize the partition's contents and set the new
1676 	// parameters
1677 	if ((error = partition->UninitializeContents(true)) != B_OK)
1678 		return error;
1679 
1680 	partition->SetDiskSystem(diskSystem);
1681 
1682 	if ((error = partition->SetContentName(_name ? name : NULL)) != B_OK)
1683 		return error;
1684 	partition->Changed(B_PARTITION_CHANGED_CONTENT_NAME);
1685 
1686 	if ((error = partition->SetContentParameters(parameters)) != B_OK)
1687 		return error;
1688 	partition->Changed(B_PARTITION_CHANGED_CONTENT_PARAMETERS);
1689 
1690 	partition->Changed(B_PARTITION_CHANGED_INITIALIZATION);
1691 
1692 	// implicit content disk system changes
1693 	return partition->DiskSystem()->ShadowPartitionChanged(
1694 		partition, NULL, B_PARTITION_INITIALIZE);
1695 }
1696 
1697 
1698 // _user_uninitialize_partition
1699 status_t
1700 _user_uninitialize_partition(partition_id partitionID, int32 changeCounter)
1701 {
1702 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1703 	// get the partition
1704 	KPartition *partition = manager->WriteLockPartition(partitionID);
1705 	if (!partition)
1706 		return B_ENTRY_NOT_FOUND;
1707 	PartitionRegistrar registrar1(partition, true);
1708 	PartitionRegistrar registrar2(partition->Device(), true);
1709 	DeviceWriteLocker locker(partition->Device(), true);
1710 	// unitialize the partition's contents and set the new parameters
1711 	return partition->UninitializeContents(true);
1712 }
1713 
1714 
1715 // _user_create_child_partition
1716 status_t
1717 _user_create_child_partition(partition_id partitionID, int32 changeCounter,
1718 	off_t offset, off_t size, const char *_type, const char *_parameters,
1719 	size_t parametersSize, partition_id *_childID)
1720 {
1721 	if (!_type || parametersSize > B_DISK_DEVICE_MAX_PARAMETER_SIZE)
1722 		return B_BAD_VALUE;
1723 	char type[B_DISK_DEVICE_TYPE_LENGTH];
1724 	char *parameters = NULL;
1725 	status_t error = ddm_strlcpy(type, _type, B_DISK_DEVICE_TYPE_LENGTH);
1726 	if (error)
1727 		return error;
1728 	if (_parameters) {
1729 		parameters = static_cast<char*>(malloc(parametersSize));
1730 		if (parameters)
1731 			user_memcpy(parameters, _parameters, parametersSize);
1732 		else
1733 			return B_NO_MEMORY;
1734 	}
1735 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1736 	// get the partition
1737 	KPartition *partition = manager->WriteLockPartition(partitionID);
1738 	error = partition ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND;
1739 	if (!error) {
1740 		PartitionRegistrar registrar1(partition, true);
1741 		PartitionRegistrar registrar2(partition->Device(), true);
1742 		DeviceWriteLocker locker(partition->Device(), true);
1743 		// check the parameters
1744 		off_t proposedOffset = offset;
1745 		off_t proposedSize = size;
1746 		int32 index = 0;
1747 		error = validate_create_child_partition(partition, changeCounter,
1748 			&proposedOffset, &proposedSize, type, parameters, &index);
1749 		if (!error) {
1750 			error =	(proposedOffset == offset && proposedSize == size)
1751 				    ? B_OK : B_BAD_VALUE;
1752 			if (!error) {
1753 				// create the child
1754 				KPartition *child = NULL;
1755 				error = partition->CreateChild(-1, index, &child);
1756 				if (!error) {
1757 					partition->Changed(B_PARTITION_CHANGED_CHILDREN);
1758 					if (_childID) {
1759 						partition_id childID = child->ID();
1760 						user_memcpy(_childID, &childID, sizeof(childID));
1761 					}
1762 					// set the parameters
1763 					child->SetOffset(offset);
1764 					child->SetSize(size);
1765 					error = child->SetType(type);
1766 				}
1767 				if (!error) {
1768 					error = child->SetParameters(parameters);
1769 				}
1770 				if (!error) {
1771 					// implicit partitioning system changes
1772 					error = partition->DiskSystem()->ShadowPartitionChanged(
1773 							partition, child, B_PARTITION_CREATE_CHILD);
1774 				}
1775 			}
1776 		}
1777 	}
1778 	free(parameters);
1779 	return error;
1780 }
1781 
1782 
1783 // _user_delete_partition
1784 status_t
1785 _user_delete_partition(partition_id partitionID, int32 changeCounter)
1786 {
1787 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1788 	// get the partition
1789 	KPartition *partition = manager->WriteLockPartition(partitionID);
1790 	if (!partition)
1791 		return B_ENTRY_NOT_FOUND;
1792 	PartitionRegistrar registrar1(partition, true);
1793 	PartitionRegistrar registrar2(partition->Device(), true);
1794 	DeviceWriteLocker locker(partition->Device(), true);
1795 	// check whether delete the child is OK
1796 	status_t error = validate_delete_child_partition(partition, changeCounter);
1797 	if (error != B_OK)
1798 		return error;
1799 	// delete the child
1800 	KPartition *parent = partition->Parent();
1801 	if (!parent->RemoveChild(partition))
1802 		return B_ERROR;
1803 	parent->Changed(B_PARTITION_CHANGED_CHILDREN);
1804 	return B_OK;
1805 }
1806 
1807 
1808 // _user_get_next_disk_device_job_info
1809 status_t
1810 _user_get_next_disk_device_job_info(int32 *_cookie,
1811 	user_disk_device_job_info *_info)
1812 {
1813 	if (!_cookie || !_info)
1814 		return B_BAD_VALUE;
1815 	int32 cookie;
1816 	user_disk_device_job_info info;
1817 	user_memcpy(&cookie, _cookie, sizeof(cookie));
1818 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1819 	status_t error = B_ENTRY_NOT_FOUND;
1820 	if (ManagerLocker locker = manager) {
1821 		// get the next job and an info
1822 		while (KDiskDeviceJob *job = manager->NextJob(&cookie)) {
1823 			// return info only on job scheduled or in progress
1824 			switch (job->Status()) {
1825 				case B_DISK_DEVICE_JOB_SCHEDULED:
1826 				case B_DISK_DEVICE_JOB_IN_PROGRESS:
1827 					error = job->GetInfo(&info);
1828 					break;
1829 				case B_DISK_DEVICE_JOB_UNINITIALIZED:
1830 				case B_DISK_DEVICE_JOB_SUCCEEDED:
1831 				case B_DISK_DEVICE_JOB_FAILED:
1832 				case B_DISK_DEVICE_JOB_CANCELED:
1833 					break;
1834 			}
1835 		}
1836 	}
1837 	if (!error) {
1838 		user_memcpy(_cookie, &cookie, sizeof(cookie));
1839 		user_memcpy(_info, &info, sizeof(info));
1840 	}
1841 	return error;
1842 }
1843 
1844 
1845 // _user_get_disk_device_job_info
1846 status_t
1847 _user_get_disk_device_job_info(disk_job_id id, user_disk_device_job_info *_info)
1848 {
1849 	if (!_info)
1850 		return B_BAD_VALUE;
1851 	user_disk_device_job_info info;
1852 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1853 	status_t error = B_ENTRY_NOT_FOUND;
1854 	if (ManagerLocker locker = manager) {
1855 		// find the job and get the info
1856 		if (KDiskDeviceJob *job = manager->FindJob(id))
1857 			error = job->GetInfo(&info);
1858 	}
1859 	if (!error)
1860 		user_memcpy(_info, &info, sizeof(info));
1861 	return error;
1862 }
1863 
1864 
1865 // _user_get_disk_device_job_status
1866 status_t
1867 _user_get_disk_device_job_progress_info(disk_job_id id,
1868 	disk_device_job_progress_info *_info)
1869 {
1870 	if (!_info)
1871 		return B_BAD_VALUE;
1872 	disk_device_job_progress_info info;
1873 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1874 	status_t error = B_ENTRY_NOT_FOUND;
1875 	if (ManagerLocker locker = manager) {
1876 		// find the job and get the info
1877 		if (KDiskDeviceJob *job = manager->FindJob(id))
1878 			error = job->GetProgressInfo(&info);
1879 	}
1880 	if (!error)
1881 		user_memcpy(_info, &info, sizeof(info));
1882 	return error;
1883 }
1884 
1885 
1886 // _user_pause_disk_device_job
1887 status_t
1888 _user_pause_disk_device_job(disk_job_id id)
1889 {
1890 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1891 	if (ManagerLocker locker = manager) {
1892 		// get the job and the respective job queue
1893 		if (KDiskDeviceJob *job = manager->FindJob(id)) {
1894 			if (KDiskDeviceJobQueue *jobQueue = job->JobQueue()) {
1895 				// only the active job in progress can be paused
1896 				if (jobQueue->ActiveJob() != job)
1897 					return B_BAD_VALUE;
1898 				return jobQueue->Pause();
1899 			}
1900 		}
1901 	}
1902 	return B_ENTRY_NOT_FOUND;
1903 }
1904 
1905 
1906 // _user_cancel_disk_device_job
1907 status_t
1908 _user_cancel_disk_device_job(disk_job_id id, bool reverse)
1909 {
1910 	KDiskDeviceManager *manager = KDiskDeviceManager::Default();
1911 	if (ManagerLocker locker = manager) {
1912 		// get the job and the respective job queue
1913 		if (KDiskDeviceJob *job = manager->FindJob(id)) {
1914 			if (KDiskDeviceJobQueue *jobQueue = job->JobQueue()) {
1915 				// only the active job in progress can be canceled
1916 				if (jobQueue->ActiveJob() != job)
1917 					return B_BAD_VALUE;
1918 				return jobQueue->Cancel(reverse);
1919 			}
1920 		}
1921 	}
1922 	return B_ENTRY_NOT_FOUND;
1923 }
1924 
1925