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