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