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