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