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