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