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