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