headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / kernel / disk_device_manager / ddm_userland_interface.cpp
blob0e426578592b20939889503885c27d3248bcb833
1 /*
2 * Copyright 2003-2017, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold, ingo_weinhold@gmx.de
7 * Axel Dörfler, axeld@pinc-software.de
8 */
10 /*! \file ddm_userland_interface.cpp
12 \brief Interface for userspace calls.
15 #include <ddm_userland_interface.h>
17 #include <stdlib.h>
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>
28 #include "UserDataWriter.h"
30 using namespace BPrivate::DiskDevice;
32 // debugging
33 #define ERROR(x)
36 // TODO: Replace all instances, when it has been decided how to handle
37 // notifications during jobs.
38 #define DUMMY_JOB_ID 0
41 // TODO: Add user address checks and check return values of user_memcpy()!
44 /*! \brief Wrapper around user_strlcpy() that returns a status_t
45 indicating appropriate success or failure.
47 \param allowTruncation If \c true, does not return an error if
48 \a from is longer than \to. If \c false, returns \c B_NAME_TOO_LONG
49 if \a from is longer than \to.
51 static status_t
52 ddm_strlcpy(char *to, const char *from, size_t size,
53 bool allowTruncation = false)
55 ssize_t fromLen = user_strlcpy(to, from, size);
56 if (fromLen < 0)
57 return fromLen;
58 if ((size_t)fromLen >= size && !allowTruncation)
59 return B_NAME_TOO_LONG;
60 return B_OK;
64 template<typename Type>
65 static inline status_t
66 copy_from_user_value(Type& value, const Type* userValue)
68 if (!userValue)
69 return B_BAD_VALUE;
71 if (!IS_USER_ADDRESS(userValue))
72 return B_BAD_ADDRESS;
74 return user_memcpy(&value, userValue, sizeof(Type));
78 template<typename Type>
79 static inline status_t
80 copy_to_user_value(Type* userValue, const Type& value)
82 if (!userValue)
83 return B_BAD_VALUE;
85 if (!IS_USER_ADDRESS(userValue))
86 return B_BAD_ADDRESS;
88 return user_memcpy(userValue, &value, sizeof(Type));
92 template<bool kAllowsNull>
93 struct UserStringParameter {
94 char* value;
96 inline UserStringParameter()
97 : value(NULL)
101 inline ~UserStringParameter()
103 free(value);
106 inline status_t Init(const char* userValue, size_t maxSize)
108 if (userValue == NULL) {
109 if (!kAllowsNull)
110 return B_BAD_VALUE;
112 return B_OK;
115 if (!IS_USER_ADDRESS(userValue))
116 return B_BAD_ADDRESS;
118 value = (char*)malloc(maxSize);
119 if (value == NULL)
120 return B_NO_MEMORY;
122 ssize_t bytesCopied = user_strlcpy(value, userValue, maxSize);
123 if (bytesCopied < 0)
124 return bytesCopied;
126 if ((size_t)bytesCopied >= maxSize)
127 return B_BUFFER_OVERFLOW;
129 return B_OK;
132 inline operator const char*()
134 return value;
137 inline operator char*()
139 return value;
144 #if 0
145 static void
146 move_descendants(KPartition *partition, off_t moveBy)
148 if (!partition)
149 return;
150 partition->SetOffset(partition->Offset() + moveBy);
151 // move children
152 for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++)
153 move_descendants(child, moveBy);
157 static status_t
158 move_descendants_contents(KPartition *partition)
160 if (!partition)
161 return B_BAD_VALUE;
162 // implicit content disk system changes
163 KDiskSystem *diskSystem = partition->DiskSystem();
164 if (diskSystem || partition->AlgorithmData()) {
165 status_t error = diskSystem->ShadowPartitionChanged(partition,
166 NULL, B_PARTITION_MOVE);
167 if (error != B_OK)
168 return error;
170 // move children's contents
171 for (int32 i = 0; KPartition *child = partition->ChildAt(i); i++) {
172 status_t error = move_descendants_contents(child);
173 if (error != B_OK)
174 return error;
176 return B_OK;
178 #endif // 0
181 partition_id
182 _user_get_next_disk_device_id(int32 *_cookie, size_t *neededSize)
184 if (!_cookie)
185 return B_BAD_VALUE;
186 int32 cookie;
187 user_memcpy(&cookie, _cookie, sizeof(cookie));
189 partition_id id = B_ENTRY_NOT_FOUND;
190 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
191 // get the next device
192 if (KDiskDevice *device = manager->RegisterNextDevice(&cookie)) {
193 PartitionRegistrar _(device, true);
194 id = device->ID();
195 if (neededSize) {
196 if (DeviceReadLocker locker = device) {
197 // get the needed size
198 UserDataWriter writer;
199 device->WriteUserData(writer);
200 status_t status = copy_to_user_value(neededSize,
201 writer.AllocatedSize());
202 if (status != B_OK)
203 return status;
204 } else {
205 id = B_ERROR;
209 user_memcpy(_cookie, &cookie, sizeof(cookie));
210 return id;
214 partition_id
215 _user_find_disk_device(const char *_filename, size_t *neededSize)
217 UserStringParameter<false> filename;
218 status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
219 if (error != B_OK)
220 return error;
222 partition_id id = B_ENTRY_NOT_FOUND;
223 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
224 // find the device
225 if (KDiskDevice *device = manager->RegisterDevice(filename)) {
226 PartitionRegistrar _(device, true);
227 id = device->ID();
228 if (neededSize) {
229 if (DeviceReadLocker locker = device) {
230 // get the needed size
231 UserDataWriter writer;
232 device->WriteUserData(writer);
233 error = copy_to_user_value(neededSize, writer.AllocatedSize());
234 if (error != B_OK)
235 return error;
236 } else
237 return B_ERROR;
240 return id;
244 partition_id
245 _user_find_partition(const char *_filename, size_t *neededSize)
247 UserStringParameter<false> filename;
248 status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
249 if (error != B_OK)
250 return error;
252 partition_id id = B_ENTRY_NOT_FOUND;
253 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
254 // find the partition
255 if (KPartition *partition = manager->RegisterPartition(filename)) {
256 PartitionRegistrar _(partition, true);
257 id = partition->ID();
258 if (neededSize) {
259 // get and lock the partition's device
260 KDiskDevice *device = manager->RegisterDevice(partition->ID(),
261 false);
262 if (!device)
263 return B_ENTRY_NOT_FOUND;
264 PartitionRegistrar _2(device, true);
265 if (DeviceReadLocker locker = device) {
266 // get the needed size
267 UserDataWriter writer;
268 device->WriteUserData(writer);
269 error = copy_to_user_value(neededSize, writer.AllocatedSize());
270 if (error != B_OK)
271 return error;
272 } else
273 return B_ERROR;
276 return id;
280 partition_id
281 _user_find_file_disk_device(const char *_filename, size_t *neededSize)
283 UserStringParameter<false> filename;
284 status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
285 if (error != B_OK)
286 return error;
288 KPath path(filename, KPath::NORMALIZE);
290 partition_id id = B_ENTRY_NOT_FOUND;
291 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
292 // find the device
293 if (KFileDiskDevice* device = manager->RegisterFileDevice(path.Path())) {
294 PartitionRegistrar _(device, true);
295 id = device->ID();
296 if (neededSize) {
297 if (DeviceReadLocker locker = device) {
298 // get the needed size
299 UserDataWriter writer;
300 device->WriteUserData(writer);
301 error = copy_to_user_value(neededSize, writer.AllocatedSize());
302 if (error != B_OK)
303 return error;
304 } else
305 return B_ERROR;
308 return id;
312 /*! \brief Writes data describing the disk device identified by ID and all
313 its partitions into the supplied buffer.
315 The function passes the buffer size required to hold the data back
316 through the \a _neededSize parameter, if the device could be found at
317 least and no serious error occured. If fails with \c B_BUFFER_OVERFLOW,
318 if the supplied buffer is too small or a \c NULL buffer is supplied
319 (and \c bufferSize is 0).
321 The device is identified by \a id. If \a deviceOnly is \c true, then
322 it must be the ID of a disk device, otherwise the disk device is
323 chosen, on which the partition \a id refers to resides.
325 \param id The ID of an arbitrary partition on the disk device (including
326 the disk device itself), whose data shall be returned
327 (if \a deviceOnly is \c false), or the ID of the disk device
328 itself (if \a deviceOnly is true).
329 \param deviceOnly Specifies whether only IDs of disk devices (\c true),
330 or also IDs of partitions (\c false) are accepted for \a id.
331 \param buffer The buffer into which the disk device data shall be written.
332 May be \c NULL.
333 \param bufferSize The size of \a buffer.
334 \param _neededSize Pointer to a variable into which the actually needed
335 buffer size is written. May be \c NULL.
336 \return
337 - \c B_OK: Everything went fine. The device was found and, if not \c NULL,
338 in \a _neededSize the actually needed buffer size is returned. And
339 \a buffer will contain the disk device data.
340 - \c B_BAD_VALUE: \c NULL \a buffer, but not 0 \a bufferSize.
341 - \c B_BUFFER_OVERFLOW: The supplied buffer was too small. \a _neededSize,
342 if not \c NULL, will contain the required buffer size.
343 - \c B_NO_MEMORY: Insufficient memory to complete the operation.
344 - \c B_ENTRY_NOT_FOUND: \a id is no valid disk device ID (if \a deviceOnly
345 is \c true) or not even a valid partition ID (if \a deviceOnly is
346 \c false).
347 - \c B_ERROR: An unexpected error occured.
348 - another error code...
350 status_t
351 _user_get_disk_device_data(partition_id id, bool deviceOnly,
352 user_disk_device_data *buffer, size_t bufferSize, size_t *_neededSize)
354 if (!buffer && bufferSize > 0)
355 return B_BAD_VALUE;
356 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
357 // get the device
358 if (KDiskDevice *device = manager->RegisterDevice(id, deviceOnly)) {
359 PartitionRegistrar _(device, true);
360 if (DeviceReadLocker locker = device) {
361 // do a dry run first to get the needed size
362 UserDataWriter writer;
363 device->WriteUserData(writer);
364 size_t neededSize = writer.AllocatedSize();
365 if (_neededSize) {
366 status_t error = copy_ref_var_to_user(neededSize, _neededSize);
367 if (error != B_OK)
368 return error;
370 // if no buffer has been supplied or the buffer is too small,
371 // then we're done
372 if (!buffer || bufferSize < neededSize)
373 return B_BUFFER_OVERFLOW;
374 // otherwise allocate a kernel buffer
375 user_disk_device_data *kernelBuffer
376 = static_cast<user_disk_device_data*>(malloc(neededSize));
377 if (!kernelBuffer)
378 return B_NO_MEMORY;
379 MemoryDeleter deleter(kernelBuffer);
380 // write the device data into the buffer
381 writer.SetTo(kernelBuffer, bufferSize);
382 device->WriteUserData(writer);
383 // sanity check
384 if (writer.AllocatedSize() != neededSize) {
385 ERROR(("Size of written disk device user data changed from "
386 "%lu to %lu while device was locked!\n"));
387 return B_ERROR;
389 // relocate
390 status_t error = writer.Relocate(buffer);
391 if (error != B_OK)
392 return error;
393 // copy out
394 if (buffer)
395 return user_memcpy(buffer, kernelBuffer, neededSize);
396 } else
397 return B_ERROR;
399 return B_ENTRY_NOT_FOUND;
403 partition_id
404 _user_register_file_device(const char *_filename)
406 UserStringParameter<false> filename;
407 status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
408 if (error != B_OK)
409 return error;
411 KPath path(filename, KPath::NORMALIZE);
413 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
414 if (ManagerLocker locker = manager) {
415 if (KFileDiskDevice *device = manager->FindFileDevice(path.Path()))
416 return device->ID();
417 return manager->CreateFileDevice(path.Path());
419 return B_ERROR;
423 status_t
424 _user_unregister_file_device(partition_id deviceID, const char *_filename)
426 if (deviceID < 0 && !_filename)
427 return B_BAD_VALUE;
428 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
429 if (deviceID >= 0) {
430 return manager->DeleteFileDevice(deviceID);
431 } else {
432 UserStringParameter<false> filename;
433 status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH);
434 if (error != B_OK)
435 return error;
437 return manager->DeleteFileDevice(filename);
442 status_t
443 _user_get_file_disk_device_path(partition_id id, char* buffer,
444 size_t bufferSize)
446 if (id < 0 || buffer == NULL || bufferSize == 0)
447 return B_BAD_VALUE;
449 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
451 if (KDiskDevice *device = manager->RegisterDevice(id, true)) {
452 PartitionRegistrar _(device, true);
453 if (DeviceReadLocker locker = device) {
454 KFileDiskDevice* fileDevice
455 = dynamic_cast<KFileDiskDevice*>(device);
456 if (fileDevice == NULL)
457 return B_BAD_VALUE;
459 ssize_t copied = user_strlcpy(buffer, fileDevice->FilePath(),
460 bufferSize);
461 if (copied < 0)
462 return copied;
463 return (size_t)copied < bufferSize ? B_OK : B_BUFFER_OVERFLOW;
467 return B_ERROR;
471 status_t
472 _user_get_disk_system_info(disk_system_id id, user_disk_system_info *_info)
474 if (!_info)
475 return B_BAD_VALUE;
476 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
477 if (ManagerLocker locker = manager) {
478 if (KDiskSystem *diskSystem = manager->FindDiskSystem(id)) {
479 user_disk_system_info info;
480 diskSystem->GetInfo(&info);
481 user_memcpy(_info, &info, sizeof(info));
482 return B_OK;
485 return B_ENTRY_NOT_FOUND;
489 status_t
490 _user_get_next_disk_system_info(int32 *_cookie, user_disk_system_info *_info)
492 if (!_cookie || !_info)
493 return B_BAD_VALUE;
494 int32 cookie;
495 user_memcpy(&cookie, _cookie, sizeof(cookie));
496 status_t result = B_ENTRY_NOT_FOUND;
497 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
498 if (ManagerLocker locker = manager) {
499 if (KDiskSystem *diskSystem = manager->NextDiskSystem(&cookie)) {
500 user_disk_system_info info;
501 diskSystem->GetInfo(&info);
502 user_memcpy(_info, &info, sizeof(info));
503 result = B_OK;
506 user_memcpy(_cookie, &cookie, sizeof(cookie));
507 return result;
511 status_t
512 _user_find_disk_system(const char *_name, user_disk_system_info *_info)
514 if (!_name || !_info)
515 return B_BAD_VALUE;
516 char name[B_DISK_SYSTEM_NAME_LENGTH];
517 status_t error = ddm_strlcpy(name, _name, B_DISK_SYSTEM_NAME_LENGTH);
518 if (error)
519 return error;
520 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
521 if (ManagerLocker locker = manager) {
522 if (KDiskSystem *diskSystem = manager->FindDiskSystem(name)) {
523 user_disk_system_info info;
524 diskSystem->GetInfo(&info);
525 user_memcpy(_info, &info, sizeof(info));
526 return B_OK;
529 return B_ENTRY_NOT_FOUND;
533 status_t
534 _user_defragment_partition(partition_id partitionID, int32* _changeCounter)
536 // copy parameters in
537 int32 changeCounter;
539 status_t error;
540 if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
541 return error;
543 // get the partition
544 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
545 KPartition* partition = manager->WriteLockPartition(partitionID);
546 if (!partition)
547 return B_ENTRY_NOT_FOUND;
549 PartitionRegistrar registrar1(partition, true);
550 PartitionRegistrar registrar2(partition->Device(), true);
551 DeviceWriteLocker locker(partition->Device(), true);
553 // check change counter
554 if (changeCounter != partition->ChangeCounter())
555 return B_BAD_VALUE;
557 // the partition must be initialized
558 KDiskSystem* diskSystem = partition->DiskSystem();
559 if (!diskSystem)
560 return B_BAD_VALUE;
562 // mark the partition busy and unlock
563 if (!partition->CheckAndMarkBusy(false))
564 return B_BUSY;
565 locker.Unlock();
567 // defragment
568 error = diskSystem->Defragment(partition, DUMMY_JOB_ID);
570 // re-lock and unmark busy
571 locker.Lock();
572 partition->UnmarkBusy(false);
574 if (error != B_OK)
575 return error;
577 // return change counter
578 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
579 != B_OK) {
580 return error;
583 return B_OK;
587 status_t
588 _user_repair_partition(partition_id partitionID, int32* _changeCounter,
589 bool checkOnly)
591 // copy parameters in
592 int32 changeCounter;
594 status_t error;
595 if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
596 return error;
598 // get the partition
599 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
600 KPartition* partition = manager->WriteLockPartition(partitionID);
601 if (!partition)
602 return B_ENTRY_NOT_FOUND;
604 PartitionRegistrar registrar1(partition, true);
605 PartitionRegistrar registrar2(partition->Device(), true);
606 DeviceWriteLocker locker(partition->Device(), true);
608 // check change counter
609 if (changeCounter != partition->ChangeCounter())
610 return B_BAD_VALUE;
612 // the partition must be initialized
613 KDiskSystem* diskSystem = partition->DiskSystem();
614 if (!diskSystem)
615 return B_BAD_VALUE;
617 // mark the partition busy and unlock
618 if (!partition->CheckAndMarkBusy(false))
619 return B_BUSY;
620 locker.Unlock();
622 // repair/check
623 error = diskSystem->Repair(partition, checkOnly, DUMMY_JOB_ID);
625 // re-lock and unmark busy
626 locker.Lock();
627 partition->UnmarkBusy(false);
629 if (error != B_OK)
630 return error;
632 // return change counter
633 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
634 != B_OK) {
635 return error;
638 return B_OK;
642 status_t
643 _user_resize_partition(partition_id partitionID, int32* _changeCounter,
644 partition_id childID, int32* _childChangeCounter, off_t size,
645 off_t contentSize)
647 // copy parameters in
648 int32 changeCounter;
649 int32 childChangeCounter;
651 status_t error;
652 if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK
653 || (error = copy_from_user_value(childChangeCounter,
654 _childChangeCounter)) != B_OK) {
655 return error;
658 // get the partition
659 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
660 KPartition* partition = manager->WriteLockPartition(partitionID);
661 if (!partition)
662 return B_ENTRY_NOT_FOUND;
664 PartitionRegistrar registrar1(partition, true);
665 PartitionRegistrar registrar2(partition->Device(), true);
666 DeviceWriteLocker locker(partition->Device(), true);
668 // register child
669 KPartition* child = manager->RegisterPartition(childID);
670 if (!child)
671 return B_ENTRY_NOT_FOUND;
673 PartitionRegistrar registrar3(child, true);
675 // check change counters
676 if (changeCounter != partition->ChangeCounter()
677 || childChangeCounter != child->ChangeCounter()) {
678 return B_BAD_VALUE;
681 // the partition must be initialized
682 KDiskSystem* diskSystem = partition->DiskSystem();
683 if (!diskSystem)
684 return B_BAD_VALUE;
686 // child must indeed be a child of partition
687 if (child->Parent() != partition)
688 return B_BAD_VALUE;
690 // check sizes
691 if (size < 0 || contentSize < 0 || size < contentSize
692 || size > partition->ContentSize()) {
693 return B_BAD_VALUE;
696 // mark the partitions busy and unlock
697 if (partition->IsBusy() || child->IsBusy())
698 return B_BUSY;
699 partition->SetBusy(true);
700 child->SetBusy(true);
701 locker.Unlock();
703 // resize contents first, if shrinking
704 if (child->DiskSystem() && contentSize < child->ContentSize())
705 error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID);
707 // resize the partition
708 if (error == B_OK && size != child->Size())
709 error = diskSystem->ResizeChild(child, size, DUMMY_JOB_ID);
711 // resize contents last, if growing
712 if (error == B_OK && child->DiskSystem()
713 && contentSize > child->ContentSize()) {
714 error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID);
717 // re-lock and unmark busy
718 locker.Lock();
719 partition->SetBusy(false);
720 child->SetBusy(false);
722 if (error != B_OK)
723 return error;
725 // return change counters
726 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
727 != B_OK
728 || (error = copy_to_user_value(_childChangeCounter,
729 child->ChangeCounter())) != B_OK) {
730 return error;
733 return B_OK;
737 status_t
738 _user_move_partition(partition_id partitionID, int32* changeCounter,
739 partition_id childID, int32* childChangeCounter, off_t newOffset,
740 partition_id* descendantIDs, int32* descendantChangeCounters,
741 int32 descendantCount)
743 #if 0
744 KDiskDeviceManager *manager = KDiskDeviceManager::Default();
745 // get the partition
746 KPartition *partition = manager->WriteLockPartition(partitionID);
747 if (!partition)
748 return B_ENTRY_NOT_FOUND;
749 PartitionRegistrar registrar1(partition, true);
750 PartitionRegistrar registrar2(partition->Device(), true);
751 DeviceWriteLocker locker(partition->Device(), true);
752 // check the new offset
753 if (newOffset == partition->Offset())
754 return B_OK;
755 off_t proposedOffset = newOffset;
756 status_t error = validate_move_partition(partition, changeCounter,
757 &proposedOffset, true);
758 if (error != B_OK)
759 return error;
760 if (proposedOffset != newOffset)
761 return B_BAD_VALUE;
762 // new offset is fine -- move the thing
763 off_t moveBy = newOffset - partition->Offset();
764 move_descendants(partition, moveBy);
765 partition->Changed(B_PARTITION_CHANGED_OFFSET);
766 // implicit partitioning system changes
767 error = partition->Parent()->DiskSystem()->ShadowPartitionChanged(
768 partition->Parent(), partition, B_PARTITION_MOVE_CHILD);
769 if (error != B_OK)
770 return error;
771 // implicit descendants' content disk system changes
772 return move_descendants_contents(partition);
773 #endif
774 return B_BAD_VALUE;
778 status_t
779 _user_set_partition_name(partition_id partitionID, int32* _changeCounter,
780 partition_id childID, int32* _childChangeCounter, const char* _name)
782 // copy parameters in
783 UserStringParameter<false> name;
784 int32 changeCounter;
785 int32 childChangeCounter;
787 status_t error;
788 if ((error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
789 || (error = copy_from_user_value(changeCounter, _changeCounter))
790 != B_OK
791 || (error = copy_from_user_value(childChangeCounter,
792 _childChangeCounter)) != B_OK) {
793 return error;
796 // get the partition
797 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
798 KPartition* partition = manager->WriteLockPartition(partitionID);
799 if (!partition)
800 return B_ENTRY_NOT_FOUND;
802 PartitionRegistrar registrar1(partition, true);
803 PartitionRegistrar registrar2(partition->Device(), true);
804 DeviceWriteLocker locker(partition->Device(), true);
806 // register child
807 KPartition* child = manager->RegisterPartition(childID);
808 if (!child)
809 return B_ENTRY_NOT_FOUND;
811 PartitionRegistrar registrar3(child, true);
813 // check change counters
814 if (changeCounter != partition->ChangeCounter()
815 || childChangeCounter != child->ChangeCounter()) {
816 return B_BAD_VALUE;
819 // the partition must be initialized
820 KDiskSystem* diskSystem = partition->DiskSystem();
821 if (!diskSystem)
822 return B_BAD_VALUE;
824 // child must indeed be a child of partition
825 if (child->Parent() != partition)
826 return B_BAD_VALUE;
828 // mark the partitions busy and unlock
829 if (partition->IsBusy() || child->IsBusy())
830 return B_BUSY;
831 partition->SetBusy(true);
832 child->SetBusy(true);
833 locker.Unlock();
835 // set the child name
836 error = diskSystem->SetName(child, name.value, DUMMY_JOB_ID);
838 // re-lock and unmark busy
839 locker.Lock();
840 partition->SetBusy(false);
841 child->SetBusy(false);
843 if (error != B_OK)
844 return error;
846 // return change counters
847 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
848 != B_OK
849 || (error = copy_to_user_value(_childChangeCounter,
850 child->ChangeCounter())) != B_OK) {
851 return error;
854 return B_OK;
858 status_t
859 _user_set_partition_content_name(partition_id partitionID,
860 int32* _changeCounter, const char* _name)
862 // copy parameters in
863 UserStringParameter<true> name;
864 int32 changeCounter;
866 status_t error;
867 if ((error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
868 || (error = copy_from_user_value(changeCounter, _changeCounter))
869 != B_OK) {
870 return error;
873 // get the partition
874 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
875 KPartition* partition = manager->WriteLockPartition(partitionID);
876 if (!partition)
877 return B_ENTRY_NOT_FOUND;
879 PartitionRegistrar registrar1(partition, true);
880 PartitionRegistrar registrar2(partition->Device(), true);
881 DeviceWriteLocker locker(partition->Device(), true);
883 // check change counter
884 if (changeCounter != partition->ChangeCounter())
885 return B_BAD_VALUE;
887 // the partition must be initialized
888 KDiskSystem* diskSystem = partition->DiskSystem();
889 if (!diskSystem)
890 return B_BAD_VALUE;
892 // mark the partition busy and unlock
893 if (!partition->CheckAndMarkBusy(false))
894 return B_BUSY;
895 locker.Unlock();
897 // set content parameters
898 error = diskSystem->SetContentName(partition, name.value, DUMMY_JOB_ID);
900 // re-lock and unmark busy
901 locker.Lock();
902 partition->UnmarkBusy(false);
904 if (error != B_OK)
905 return error;
907 // return change counter
908 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
909 != B_OK) {
910 return error;
913 return B_OK;
917 status_t
918 _user_set_partition_type(partition_id partitionID, int32* _changeCounter,
919 partition_id childID, int32* _childChangeCounter, const char* _type)
921 // copy parameters in
922 UserStringParameter<false> type;
923 int32 changeCounter;
924 int32 childChangeCounter;
926 status_t error;
927 if ((error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH)) != B_OK
928 || (error = copy_from_user_value(changeCounter, _changeCounter))
929 != B_OK
930 || (error = copy_from_user_value(childChangeCounter,
931 _childChangeCounter)) != B_OK) {
932 return error;
935 // get the partition
936 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
937 KPartition* partition = manager->WriteLockPartition(partitionID);
938 if (!partition)
939 return B_ENTRY_NOT_FOUND;
941 PartitionRegistrar registrar1(partition, true);
942 PartitionRegistrar registrar2(partition->Device(), true);
943 DeviceWriteLocker locker(partition->Device(), true);
945 // register child
946 KPartition* child = manager->RegisterPartition(childID);
947 if (!child)
948 return B_ENTRY_NOT_FOUND;
950 PartitionRegistrar registrar3(child, true);
952 // check change counters
953 if (changeCounter != partition->ChangeCounter()
954 || childChangeCounter != child->ChangeCounter()) {
955 return B_BAD_VALUE;
958 // the partition must be initialized
959 KDiskSystem* diskSystem = partition->DiskSystem();
960 if (!diskSystem)
961 return B_BAD_VALUE;
963 // child must indeed be a child of partition
964 if (child->Parent() != partition)
965 return B_BAD_VALUE;
967 // mark the partition busy and unlock
968 if (partition->IsBusy() || child->IsBusy())
969 return B_BUSY;
970 partition->SetBusy(true);
971 child->SetBusy(true);
972 locker.Unlock();
974 // set the child type
975 error = diskSystem->SetType(child, type.value, DUMMY_JOB_ID);
977 // re-lock and unmark busy
978 locker.Lock();
979 partition->SetBusy(false);
980 child->SetBusy(false);
982 if (error != B_OK)
983 return error;
985 // return change counters
986 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
987 != B_OK
988 || (error = copy_to_user_value(_childChangeCounter,
989 child->ChangeCounter())) != B_OK) {
990 return error;
993 return B_OK;
997 status_t
998 _user_set_partition_parameters(partition_id partitionID, int32* _changeCounter,
999 partition_id childID, int32* _childChangeCounter, const char* _parameters)
1001 // copy parameters in
1002 UserStringParameter<true> parameters;
1003 int32 changeCounter;
1004 int32 childChangeCounter;
1006 status_t error;
1007 if ((error = parameters.Init(_parameters, B_DISK_DEVICE_MAX_PARAMETER_SIZE))
1008 != B_OK
1009 || (error = copy_from_user_value(changeCounter, _changeCounter))
1010 != B_OK
1011 || (error = copy_from_user_value(childChangeCounter,
1012 _childChangeCounter)) != B_OK) {
1013 return error;
1016 // get the partition
1017 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1018 KPartition* partition = manager->WriteLockPartition(partitionID);
1019 if (!partition)
1020 return B_ENTRY_NOT_FOUND;
1022 PartitionRegistrar registrar1(partition, true);
1023 PartitionRegistrar registrar2(partition->Device(), true);
1024 DeviceWriteLocker locker(partition->Device(), true);
1026 // register child
1027 KPartition* child = manager->RegisterPartition(childID);
1028 if (!child)
1029 return B_ENTRY_NOT_FOUND;
1031 PartitionRegistrar registrar3(child, true);
1033 // check change counters
1034 if (changeCounter != partition->ChangeCounter()
1035 || childChangeCounter != child->ChangeCounter()) {
1036 return B_BAD_VALUE;
1039 // the partition must be initialized
1040 KDiskSystem* diskSystem = partition->DiskSystem();
1041 if (!diskSystem)
1042 return B_BAD_VALUE;
1044 // child must indeed be a child of partition
1045 if (child->Parent() != partition)
1046 return B_BAD_VALUE;
1048 // mark the partition busy and unlock
1049 if (partition->IsBusy() || child->IsBusy())
1050 return B_BUSY;
1051 partition->SetBusy(true);
1052 child->SetBusy(true);
1053 locker.Unlock();
1055 // set the child parameters
1056 error = diskSystem->SetParameters(child, parameters.value, DUMMY_JOB_ID);
1058 // re-lock and unmark busy
1059 locker.Lock();
1060 partition->SetBusy(false);
1061 child->SetBusy(false);
1063 if (error != B_OK)
1064 return error;
1066 // return change counters
1067 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1068 != B_OK
1069 || (error = copy_to_user_value(_childChangeCounter,
1070 child->ChangeCounter())) != B_OK) {
1071 return error;
1074 return B_OK;
1078 status_t
1079 _user_set_partition_content_parameters(partition_id partitionID,
1080 int32* _changeCounter, const char* _parameters)
1082 // copy parameters in
1083 UserStringParameter<true> parameters;
1084 int32 changeCounter;
1086 status_t error
1087 = parameters.Init(_parameters, B_DISK_DEVICE_MAX_PARAMETER_SIZE);
1088 if (error != B_OK || (error = copy_from_user_value(changeCounter,
1089 _changeCounter)) != B_OK) {
1090 return error;
1093 // get the partition
1094 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1095 KPartition* partition = manager->WriteLockPartition(partitionID);
1096 if (!partition)
1097 return B_ENTRY_NOT_FOUND;
1099 PartitionRegistrar registrar1(partition, true);
1100 PartitionRegistrar registrar2(partition->Device(), true);
1101 DeviceWriteLocker locker(partition->Device(), true);
1103 // check change counter
1104 if (changeCounter != partition->ChangeCounter())
1105 return B_BAD_VALUE;
1107 // the partition must be initialized
1108 KDiskSystem* diskSystem = partition->DiskSystem();
1109 if (!diskSystem)
1110 return B_BAD_VALUE;
1112 // mark the partition busy and unlock
1113 if (!partition->CheckAndMarkBusy(true))
1114 return B_BUSY;
1115 locker.Unlock();
1117 // set content parameters
1118 error = diskSystem->SetContentParameters(partition, parameters.value,
1119 DUMMY_JOB_ID);
1121 // re-lock and unmark busy
1122 locker.Lock();
1123 partition->UnmarkBusy(true);
1125 if (error != B_OK)
1126 return error;
1128 // return change counter
1129 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1130 != B_OK) {
1131 return error;
1134 return B_OK;
1138 status_t
1139 _user_initialize_partition(partition_id partitionID, int32* _changeCounter,
1140 const char* _diskSystemName, const char* _name, const char* _parameters)
1142 // copy parameters in
1143 UserStringParameter<false> diskSystemName;
1144 UserStringParameter<true> name;
1145 UserStringParameter<true> parameters;
1146 int32 changeCounter;
1148 status_t error;
1149 if ((error = diskSystemName.Init(_diskSystemName,
1150 B_DISK_SYSTEM_NAME_LENGTH)) != B_OK
1151 || (error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
1152 || (error = parameters.Init(_parameters,
1153 B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1154 || (error = copy_from_user_value(changeCounter, _changeCounter))
1155 != B_OK) {
1156 return error;
1159 // get the partition
1160 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1161 KPartition* partition = manager->WriteLockPartition(partitionID);
1162 if (!partition)
1163 return B_ENTRY_NOT_FOUND;
1165 PartitionRegistrar registrar1(partition, true);
1166 PartitionRegistrar registrar2(partition->Device(), true);
1167 DeviceWriteLocker locker(partition->Device(), true);
1169 // check change counter
1170 if (changeCounter != partition->ChangeCounter())
1171 return B_BAD_VALUE;
1173 // the partition must be uninitialized
1174 if (partition->DiskSystem())
1175 return B_BAD_VALUE;
1177 // load the new disk system
1178 KDiskSystem *diskSystem = manager->LoadDiskSystem(diskSystemName.value,
1179 true);
1180 if (!diskSystem)
1181 return B_ENTRY_NOT_FOUND;
1182 DiskSystemLoader loader(diskSystem, true);
1184 // mark the partition busy and unlock
1185 if (!partition->CheckAndMarkBusy(true))
1186 return B_BUSY;
1187 locker.Unlock();
1189 // let the disk system initialize the partition
1190 error = diskSystem->Initialize(partition, name.value, parameters.value,
1191 DUMMY_JOB_ID);
1193 // re-lock and unmark busy
1194 locker.Lock();
1195 partition->UnmarkBusy(true);
1197 if (error != B_OK)
1198 return error;
1200 // Set the disk system. Re-check whether a disk system is already set on the
1201 // partition. Some disk systems just write the on-disk structures and let
1202 // the DDM rescan the partition, in which case the disk system will already
1203 // be set. In very unfortunate cases the on-disk structure of the previous
1204 // disk system has not been destroyed and the previous disk system has a
1205 // higher priority than the new one. The old disk system will thus prevail.
1206 // Not setting the new disk system will at least prevent that the partition
1207 // object gets into an inconsistent state.
1208 if (partition->DiskSystem() == NULL)
1209 partition->SetDiskSystem(diskSystem);
1211 // return change counter
1212 error = copy_to_user_value(_changeCounter, partition->ChangeCounter());
1213 if (error != B_OK)
1214 return error;
1216 return B_OK;
1220 status_t
1221 _user_uninitialize_partition(partition_id partitionID, int32* _changeCounter,
1222 partition_id parentID, int32* _parentChangeCounter)
1224 // copy parameters in
1225 int32 changeCounter;
1226 int32 parentChangeCounter;
1227 bool haveParent = parentID >= 0;
1229 status_t error;
1230 if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
1231 return error;
1232 if (haveParent && (error = copy_from_user_value(parentChangeCounter,
1233 _parentChangeCounter)) != B_OK)
1234 return error;
1236 // get the partition
1237 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1238 KPartition* partition = manager->WriteLockPartition(partitionID);
1239 if (!partition)
1240 return B_ENTRY_NOT_FOUND;
1242 PartitionRegistrar registrar1(partition, true);
1243 PartitionRegistrar registrar2(partition->Device(), true);
1244 DeviceWriteLocker locker(partition->Device(), true);
1246 // register parent
1247 KPartition* parent = NULL;
1248 if (haveParent)
1249 parent = manager->RegisterPartition(parentID);
1251 PartitionRegistrar registrar3(parent, true);
1253 // check change counter
1254 if (changeCounter != partition->ChangeCounter())
1255 return B_BAD_VALUE;
1256 if (haveParent && parentChangeCounter != parent->ChangeCounter())
1257 return B_BAD_VALUE;
1259 // the partition must be initialized
1260 if (!partition->DiskSystem())
1261 return B_BAD_VALUE;
1263 // check busy
1264 if (!partition->CheckAndMarkBusy(true))
1265 return B_BUSY;
1267 if (partition->IsMounted() || partition->IsChildMounted())
1268 return B_BAD_VALUE;
1270 KDiskSystem* diskSystem = partition->DiskSystem();
1272 locker.Unlock();
1274 // Let the disk system uninitialize the partition. This operation is not
1275 // mandatory. If implemented, it will destroy the on-disk structures, so
1276 // that the disk system cannot accidentally identify the partition later on.
1277 if (diskSystem != NULL)
1278 diskSystem->Uninitialize(partition, DUMMY_JOB_ID);
1280 // re-lock and uninitialize the partition object
1281 locker.Lock();
1282 error = partition->UninitializeContents(true);
1284 partition->UnmarkBusy(true);
1286 if (error != B_OK)
1287 return error;
1289 // return change counter
1290 error = copy_to_user_value(_changeCounter, partition->ChangeCounter());
1291 if (error != B_OK)
1292 return error;
1293 if (haveParent && (error = copy_to_user_value(_parentChangeCounter,
1294 parent->ChangeCounter())) != B_OK)
1295 return error;
1297 return B_OK;
1301 status_t
1302 _user_create_child_partition(partition_id partitionID, int32* _changeCounter,
1303 off_t offset, off_t size, const char* _type, const char* _name,
1304 const char* _parameters, partition_id* childID, int32* childChangeCounter)
1306 // copy parameters in
1307 UserStringParameter<false> type;
1308 UserStringParameter<true> name;
1309 UserStringParameter<true> parameters;
1310 int32 changeCounter;
1312 status_t error;
1313 if ((error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH)) != B_OK
1314 || (error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK
1315 || (error = parameters.Init(_parameters,
1316 B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK
1317 || (error = copy_from_user_value(changeCounter, _changeCounter))
1318 != B_OK) {
1319 return error;
1322 // get the partition
1323 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1324 KPartition* partition = manager->WriteLockPartition(partitionID);
1325 if (!partition)
1326 return B_ENTRY_NOT_FOUND;
1328 PartitionRegistrar registrar1(partition, true);
1329 PartitionRegistrar registrar2(partition->Device(), true);
1330 DeviceWriteLocker locker(partition->Device(), true);
1332 // check change counter
1333 if (changeCounter != partition->ChangeCounter())
1334 return B_BAD_VALUE;
1336 // the partition must be initialized
1337 KDiskSystem* diskSystem = partition->DiskSystem();
1338 if (!diskSystem)
1339 return B_BAD_VALUE;
1341 // mark the partition busy and unlock
1342 if (!partition->CheckAndMarkBusy(false))
1343 return B_BUSY;
1344 locker.Unlock();
1346 // create the child
1347 KPartition *child = NULL;
1348 error = diskSystem->CreateChild(partition, offset, size, type.value,
1349 name.value, parameters.value, DUMMY_JOB_ID, &child, -1);
1351 // re-lock and unmark busy
1352 locker.Lock();
1353 partition->UnmarkBusy(false);
1355 if (error != B_OK)
1356 return error;
1358 if (child == NULL)
1359 return B_ERROR;
1361 child->UnmarkBusy(true);
1363 // return change counter and child ID
1364 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter()))
1365 != B_OK
1366 || (error = copy_to_user_value(childID, child->ID())) != B_OK) {
1367 return error;
1370 return B_OK;
1374 status_t
1375 _user_delete_child_partition(partition_id partitionID, int32* _changeCounter,
1376 partition_id childID, int32 childChangeCounter)
1378 // copy parameters in
1379 int32 changeCounter;
1381 status_t error;
1382 if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK)
1383 return error;
1385 // get the partition
1386 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1387 KPartition* partition = manager->WriteLockPartition(partitionID);
1388 if (!partition)
1389 return B_ENTRY_NOT_FOUND;
1391 PartitionRegistrar registrar1(partition, true);
1392 PartitionRegistrar registrar2(partition->Device(), true);
1393 DeviceWriteLocker locker(partition->Device(), true);
1395 // register child
1396 KPartition* child = manager->RegisterPartition(childID);
1397 if (!child)
1398 return B_ENTRY_NOT_FOUND;
1400 PartitionRegistrar registrar3(child, true);
1402 // check change counters
1403 if (changeCounter != partition->ChangeCounter()
1404 || childChangeCounter != child->ChangeCounter()) {
1405 return B_BAD_VALUE;
1408 // the partition must be initialized
1409 KDiskSystem* diskSystem = partition->DiskSystem();
1410 if (!diskSystem)
1411 return B_BAD_VALUE;
1413 // child must indeed be a child of partition
1414 if (child->Parent() != partition)
1415 return B_BAD_VALUE;
1417 // mark the partition and child busy and unlock
1418 if (partition->IsBusy() || !child->CheckAndMarkBusy(true))
1419 return B_BUSY;
1420 partition->SetBusy(true);
1421 locker.Unlock();
1423 // delete the child
1424 error = diskSystem->DeleteChild(child, DUMMY_JOB_ID);
1426 // re-lock and unmark busy
1427 locker.Lock();
1428 partition->SetBusy(false);
1429 child->UnmarkBusy(true);
1431 if (error != B_OK)
1432 return error;
1434 // return change counter
1435 return copy_to_user_value(_changeCounter, partition->ChangeCounter());
1439 status_t
1440 _user_start_watching_disks(uint32 eventMask, port_id port, int32 token)
1442 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1443 return manager->Notifications().UpdateUserListener(eventMask, port, token);
1447 status_t
1448 _user_stop_watching_disks(port_id port, int32 token)
1450 KDiskDeviceManager* manager = KDiskDeviceManager::Default();
1451 return manager->Notifications().RemoveUserListeners(port, token);