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