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 true); 1167 if (!diskSystem) 1168 return B_ENTRY_NOT_FOUND; 1169 DiskSystemLoader loader(diskSystem, true); 1170 1171 // mark the partition busy and unlock 1172 if (!partition->CheckAndMarkBusy(true)) 1173 return B_BUSY; 1174 locker.Unlock(); 1175 1176 // let the disk system initialize the partition 1177 error = diskSystem->Initialize(partition, name.value, parameters.value, 1178 DUMMY_JOB_ID); 1179 1180 // re-lock and unmark busy 1181 locker.Lock(); 1182 partition->UnmarkBusy(true); 1183 1184 if (error != B_OK) 1185 return error; 1186 1187 partition->SetDiskSystem(diskSystem); 1188 1189 // return change counter 1190 error = copy_to_user_value(_changeCounter, partition->ChangeCounter()); 1191 if (error != B_OK) 1192 return error; 1193 1194 return B_OK; 1195 } 1196 1197 1198 // _user_uninitialize_partition 1199 status_t 1200 _user_uninitialize_partition(partition_id partitionID, int32* _changeCounter) 1201 { 1202 // copy parameters in 1203 int32 changeCounter; 1204 1205 status_t error; 1206 if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK) 1207 return error; 1208 1209 // get the partition 1210 KDiskDeviceManager* manager = KDiskDeviceManager::Default(); 1211 KPartition* partition = manager->WriteLockPartition(partitionID); 1212 if (!partition) 1213 return B_ENTRY_NOT_FOUND; 1214 1215 PartitionRegistrar registrar1(partition, true); 1216 PartitionRegistrar registrar2(partition->Device(), true); 1217 DeviceWriteLocker locker(partition->Device(), true); 1218 1219 // check change counter 1220 if (changeCounter != partition->ChangeCounter()) 1221 return B_BAD_VALUE; 1222 1223 // the partition must be initialized 1224 if (!partition->DiskSystem()) 1225 return B_BAD_VALUE; 1226 1227 // check busy 1228 if (!partition->CheckAndMarkBusy(true)) 1229 return B_BUSY; 1230 1231 // TODO: We should also check, if any partition is mounted! 1232 1233 // uninitialize 1234 error = partition->UninitializeContents(true); 1235 if (error != B_OK) 1236 return error; 1237 1238 // return change counter 1239 error = copy_to_user_value(_changeCounter, partition->ChangeCounter()); 1240 if (error != B_OK) 1241 return error; 1242 1243 return B_OK; 1244 } 1245 1246 1247 // _user_create_child_partition 1248 status_t 1249 _user_create_child_partition(partition_id partitionID, int32* _changeCounter, 1250 off_t offset, off_t size, const char* _type, const char* _name, 1251 const char* _parameters, size_t parametersSize, partition_id* childID, 1252 int32* childChangeCounter) 1253 1254 { 1255 // copy parameters in 1256 UserStringParameter<false> type; 1257 UserStringParameter<true> name; 1258 UserMemoryParameter<char, true> parameters; 1259 int32 changeCounter; 1260 1261 status_t error; 1262 if ((error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH)) != B_OK 1263 || (error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK 1264 || (error = parameters.Init(_parameters, parametersSize, 1265 B_DISK_DEVICE_MAX_PARAMETER_SIZE)) != B_OK 1266 || (error = copy_from_user_value(changeCounter, _changeCounter)) 1267 != B_OK) { 1268 return error; 1269 } 1270 1271 // get the partition 1272 KDiskDeviceManager* manager = KDiskDeviceManager::Default(); 1273 KPartition* partition = manager->WriteLockPartition(partitionID); 1274 if (!partition) 1275 return B_ENTRY_NOT_FOUND; 1276 1277 PartitionRegistrar registrar1(partition, true); 1278 PartitionRegistrar registrar2(partition->Device(), true); 1279 DeviceWriteLocker locker(partition->Device(), true); 1280 1281 // check change counter 1282 if (changeCounter != partition->ChangeCounter()) 1283 return B_BAD_VALUE; 1284 1285 // the partition must be initialized 1286 KDiskSystem* diskSystem = partition->DiskSystem(); 1287 if (!diskSystem) 1288 return B_BAD_VALUE; 1289 1290 // mark the partition busy and unlock 1291 if (!partition->CheckAndMarkBusy(false)) 1292 return B_BUSY; 1293 locker.Unlock(); 1294 1295 // create the child 1296 KPartition *child = NULL; 1297 error = diskSystem->CreateChild(partition, offset, size, type.value, 1298 name.value, parameters.value, DUMMY_JOB_ID, &child, -1); 1299 1300 // re-lock and unmark busy 1301 locker.Lock(); 1302 partition->UnmarkBusy(false); 1303 1304 if (error != B_OK) 1305 return error; 1306 1307 if (child == NULL) 1308 return B_ERROR; 1309 1310 child->UnmarkBusy(true); 1311 1312 // return change counter and child ID 1313 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter())) 1314 != B_OK 1315 || (error = copy_to_user_value(childID, child->ID())) != B_OK) { 1316 return error; 1317 } 1318 1319 return B_OK; 1320 } 1321 1322 1323 // _user_delete_child_partition 1324 status_t 1325 _user_delete_child_partition(partition_id partitionID, int32* _changeCounter, 1326 partition_id childID, int32 childChangeCounter) 1327 { 1328 // copy parameters in 1329 int32 changeCounter; 1330 1331 status_t error; 1332 if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK) 1333 return error; 1334 1335 // get the partition 1336 KDiskDeviceManager* manager = KDiskDeviceManager::Default(); 1337 KPartition* partition = manager->WriteLockPartition(partitionID); 1338 if (!partition) 1339 return B_ENTRY_NOT_FOUND; 1340 1341 PartitionRegistrar registrar1(partition, true); 1342 PartitionRegistrar registrar2(partition->Device(), true); 1343 DeviceWriteLocker locker(partition->Device(), true); 1344 1345 // register child 1346 KPartition* child = manager->RegisterPartition(childID); 1347 if (!child) 1348 return B_ENTRY_NOT_FOUND; 1349 1350 PartitionRegistrar registrar3(child, true); 1351 1352 // check change counters 1353 if (changeCounter != partition->ChangeCounter() 1354 || childChangeCounter != child->ChangeCounter()) { 1355 return B_BAD_VALUE; 1356 } 1357 1358 // the partition must be initialized 1359 KDiskSystem* diskSystem = partition->DiskSystem(); 1360 if (!diskSystem) 1361 return B_BAD_VALUE; 1362 1363 // child must indeed be a child of partition 1364 if (child->Parent() != partition) 1365 return B_BAD_VALUE; 1366 1367 // mark the partition and child busy and unlock 1368 if (partition->IsBusy() || !child->CheckAndMarkBusy(true)) 1369 return B_BUSY; 1370 partition->SetBusy(true); 1371 locker.Unlock(); 1372 1373 // delete the child 1374 error = diskSystem->DeleteChild(child, DUMMY_JOB_ID); 1375 1376 // re-lock and unmark busy 1377 locker.Lock(); 1378 partition->SetBusy(false); 1379 child->UnmarkBusy(true); 1380 1381 if (error != B_OK) 1382 return error; 1383 1384 // return change counter 1385 if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter())) 1386 != B_OK) { 1387 return error; 1388 } 1389 1390 return B_OK; 1391 } 1392