partition_id _user_find_partition(const char *_filename, size_t *neededSize) { UserStringParameter<false> filename; status_t error = filename.Init(_filename, B_PATH_NAME_LENGTH); if (error != B_OK) return error; KDiskDeviceManager *manager = KDiskDeviceManager::Default(); // find the partition KPartition *partition = manager->RegisterPartition(filename); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar _(partition, true); partition_id id = partition->ID(); if (neededSize != NULL) { // get and lock the partition's device KDiskDevice *device = manager->RegisterDevice(partition->ID(), false); if (device == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar _2(device, true); if (DeviceReadLocker locker = device) { // get the needed size UserDataWriter writer; device->WriteUserData(writer); error = copy_to_user_value(neededSize, writer.AllocatedSize()); if (error != B_OK) return error; } else return B_ERROR; } return id; }
status_t _user_set_partition_content_parameters(partition_id partitionID, int32* _changeCounter, const char* _parameters) { // copy parameters in UserStringParameter<true> parameters; int32 changeCounter; status_t error = parameters.Init(_parameters, B_DISK_DEVICE_MAX_PARAMETER_SIZE); if (error != B_OK || (error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK) { return error; } // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (!partition) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // check change counter if (changeCounter != partition->ChangeCounter()) return B_BAD_VALUE; // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (!diskSystem) return B_BAD_VALUE; // mark the partition busy and unlock if (!partition->CheckAndMarkBusy(true)) return B_BUSY; locker.Unlock(); // set content parameters error = diskSystem->SetContentParameters(partition, parameters.value, DUMMY_JOB_ID); // re-lock and unmark busy locker.Lock(); partition->UnmarkBusy(true); if (error != B_OK) return error; // return change counter if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter())) != B_OK) { return error; } return B_OK; }
status_t _user_repair_partition(partition_id partitionID, int32* _changeCounter, bool checkOnly) { // copy parameters in int32 changeCounter; status_t error; if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (!partition) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // check change counter if (changeCounter != partition->ChangeCounter()) return B_BAD_VALUE; // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (!diskSystem) return B_BAD_VALUE; // mark the partition busy and unlock if (!partition->CheckAndMarkBusy(false)) return B_BUSY; locker.Unlock(); // repair/check error = diskSystem->Repair(partition, checkOnly, DUMMY_JOB_ID); // re-lock and unmark busy locker.Lock(); partition->UnmarkBusy(false); if (error != B_OK) return error; // return change counter if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter())) != B_OK) { return error; } return B_OK; }
status_t _user_set_partition_content_name(partition_id partitionID, int32* _changeCounter, const char* _name) { // copy parameters in UserStringParameter<true> name; int32 changeCounter; status_t error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH); if (error == B_OK) error = copy_from_user_value(changeCounter, _changeCounter); if (error != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // check change counter if (changeCounter != partition->ChangeCounter()) return B_BAD_VALUE; // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (diskSystem == NULL) return B_BAD_VALUE; // mark the partition busy and unlock if (!partition->CheckAndMarkBusy(false)) return B_BUSY; locker.Unlock(); // set content parameters error = diskSystem->SetContentName(partition, name.value, DUMMY_JOB_ID); // re-lock and unmark busy locker.Lock(); partition->UnmarkBusy(false); if (error != B_OK) return error; // return change counter return copy_to_user_value(_changeCounter, partition->ChangeCounter()); }
status_t _user_move_partition(partition_id partitionID, int32* changeCounter, partition_id childID, int32* childChangeCounter, off_t newOffset, partition_id* descendantIDs, int32* descendantChangeCounters, int32 descendantCount) { #if 0 KDiskDeviceManager *manager = KDiskDeviceManager::Default(); // get the partition KPartition *partition = manager->WriteLockPartition(partitionID); if (!partition) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // check the new offset if (newOffset == partition->Offset()) return B_OK; off_t proposedOffset = newOffset; status_t error = validate_move_partition(partition, changeCounter, &proposedOffset, true); if (error != B_OK) return error; if (proposedOffset != newOffset) return B_BAD_VALUE; // new offset is fine -- move the thing off_t moveBy = newOffset - partition->Offset(); move_descendants(partition, moveBy); partition->Changed(B_PARTITION_CHANGED_OFFSET); // implicit partitioning system changes error = partition->Parent()->DiskSystem()->ShadowPartitionChanged( partition->Parent(), partition, B_PARTITION_MOVE_CHILD); if (error != B_OK) return error; // implicit descendants' content disk system changes return move_descendants_contents(partition); #endif return B_BAD_VALUE; }
/*! The system was booted from CD - prefer CDs over other entries. If there is no CD, fall back to the standard mechanism (as implemented by compare_image_boot(). */ static int compare_cd_boot(const void* _a, const void* _b) { KPartition* a = *(KPartition**)_a; KPartition* b = *(KPartition**)_b; bool aIsCD = a->Type() != NULL && !strcmp(a->Type(), kPartitionTypeDataSession); bool bIsCD = b->Type() != NULL && !strcmp(b->Type(), kPartitionTypeDataSession); int compare = (int)aIsCD - (int)bIsCD; if (compare != 0) return compare; return compare_image_boot(_a, _b); }
/*! No image was chosen - prefer disks with names like "Antares", or "System" */ int compare_image_boot(const void* _a, const void* _b) { KPartition* a = *(KPartition**)_a; KPartition* b = *(KPartition**)_b; if (a->ContentName() != NULL) { if (b->ContentName() == NULL) return 1; } else if (b->ContentName() != NULL) { return -1; } else return 0; int compare = strcmp(a->ContentName(), b->ContentName()); if (!compare) return 0; if (!strcasecmp(a->ContentName(), "Antares")) return 1; if (!strcasecmp(b->ContentName(), "Antares")) return -1; if (!strncmp(a->ContentName(), "System", 6)) return 1; if (!strncmp(b->ContentName(), "System", 6)) return -1; return compare; }
void vfs_mount_boot_file_system(kernel_args* args) { PartitionStack partitions; status_t status = get_boot_partitions(args, partitions); if (status < B_OK) { panic("get_boot_partitions failed!"); } if (partitions.IsEmpty()) { panic("did not find any boot partitions!"); } KPartition* bootPartition; while (partitions.Pop(&bootPartition)) { KPath path; if (bootPartition->GetPath(&path) != B_OK) panic("could not get boot device!\n"); const char* fsName = NULL; bool readOnly = false; if (strcmp(bootPartition->ContentType(), "ISO9660 File System") == 0) { fsName = "iso9660:write_overlay:attribute_overlay"; readOnly = true; } else if (bootPartition->IsReadOnly() && strcmp(bootPartition->ContentType(), "Be File System") == 0) { fsName = "bfs:write_overlay"; readOnly = true; } TRACE(("trying to mount boot partition: %s\n", path.Path())); gBootDevice = _kern_mount("/boot", path.Path(), fsName, 0, NULL, 0); if (gBootDevice >= B_OK) { gReadOnlyBootDevice = readOnly; break; } } if (gBootDevice < B_OK) panic("could not mount boot device!\n"); // create link for the name of the boot device fs_info info; if (_kern_read_fs_info(gBootDevice, &info) == B_OK) { char path[B_FILE_NAME_LENGTH + 1]; snprintf(path, sizeof(path), "/%s", info.volume_name); _kern_create_symlink(-1, path, "/boot", 0); } // Do post-boot-volume module initialization. The module code wants to know // whether the module images the boot loader has pre-loaded are the same as // on the boot volume. That is the case when booting from hard disk or CD, // but not via network. int32 bootMethodType = args->boot_volume.GetInt32(BOOT_METHOD, BOOT_METHOD_DEFAULT); bool bootingFromBootLoaderVolume = bootMethodType == BOOT_METHOD_HARD_DISK || bootMethodType == BOOT_METHOD_CD; module_init_post_boot_device(bootingFromBootLoaderVolume); file_cache_init_post_boot_device(); // search for other disk systems KDiskDeviceManager *manager = KDiskDeviceManager::Default(); manager->RescanDiskSystems(); manager->StartMonitoring(); }
status_t _user_set_partition_parameters(partition_id partitionID, int32* _changeCounter, partition_id childID, int32* _childChangeCounter, const char* _parameters) { // copy parameters in UserStringParameter<true> parameters; int32 changeCounter; int32 childChangeCounter; status_t error = parameters.Init(_parameters, B_DISK_DEVICE_MAX_PARAMETER_SIZE); if (error == B_OK) error = copy_from_user_value(changeCounter, _changeCounter); if (error == B_OK) error = copy_from_user_value(childChangeCounter, _childChangeCounter); if (error != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // register child KPartition* child = manager->RegisterPartition(childID); if (child == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar3(child, true); // check change counters if (changeCounter != partition->ChangeCounter() || childChangeCounter != child->ChangeCounter()) { return B_BAD_VALUE; } // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (diskSystem == NULL) return B_BAD_VALUE; // child must indeed be a child of partition if (child->Parent() != partition) return B_BAD_VALUE; // mark the partition busy and unlock if (partition->IsBusy() || child->IsBusy()) return B_BUSY; partition->SetBusy(true); child->SetBusy(true); locker.Unlock(); // set the child parameters error = diskSystem->SetParameters(child, parameters.value, DUMMY_JOB_ID); // re-lock and unmark busy locker.Lock(); partition->SetBusy(false); child->SetBusy(false); if (error != B_OK) return error; // return change counters error = copy_to_user_value(_changeCounter, partition->ChangeCounter()); if (error == B_OK) error = copy_to_user_value(_childChangeCounter, child->ChangeCounter()); return error; }
status_t _user_resize_partition(partition_id partitionID, int32* _changeCounter, partition_id childID, int32* _childChangeCounter, off_t size, off_t contentSize) { // copy parameters in int32 changeCounter; int32 childChangeCounter; status_t error = copy_from_user_value(changeCounter, _changeCounter); if (error == B_OK) error = copy_from_user_value(childChangeCounter, _childChangeCounter); if (error != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // register child KPartition* child = manager->RegisterPartition(childID); if (child == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar3(child, true); // check change counters if (changeCounter != partition->ChangeCounter() || childChangeCounter != child->ChangeCounter()) { return B_BAD_VALUE; } // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (diskSystem == NULL) return B_BAD_VALUE; // child must indeed be a child of partition if (child->Parent() != partition) return B_BAD_VALUE; // check sizes if (size < 0 || contentSize < 0 || size < contentSize || size > partition->ContentSize()) { return B_BAD_VALUE; } // mark the partitions busy and unlock if (partition->IsBusy() || child->IsBusy()) return B_BUSY; partition->SetBusy(true); child->SetBusy(true); locker.Unlock(); // resize contents first, if shrinking if (child->DiskSystem() && contentSize < child->ContentSize()) error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID); // resize the partition if (error == B_OK && size != child->Size()) error = diskSystem->ResizeChild(child, size, DUMMY_JOB_ID); // resize contents last, if growing if (error == B_OK && child->DiskSystem() && contentSize > child->ContentSize()) { error = child->DiskSystem()->Resize(child, contentSize, DUMMY_JOB_ID); } // re-lock and unmark busy locker.Lock(); partition->SetBusy(false); child->SetBusy(false); if (error != B_OK) return error; // return change counters error = copy_to_user_value(_changeCounter, partition->ChangeCounter()); if (error == B_OK) error = copy_to_user_value(_childChangeCounter, child->ChangeCounter()); return error; }
status_t _user_delete_child_partition(partition_id partitionID, int32* _changeCounter, partition_id childID, int32 childChangeCounter) { // copy parameters in int32 changeCounter; status_t error; if ((error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // register child KPartition* child = manager->RegisterPartition(childID); if (child == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar3(child, true); // check change counters if (changeCounter != partition->ChangeCounter() || childChangeCounter != child->ChangeCounter()) { return B_BAD_VALUE; } // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (diskSystem == NULL) return B_BAD_VALUE; // child must indeed be a child of partition if (child->Parent() != partition) return B_BAD_VALUE; // mark the partition and child busy and unlock if (partition->IsBusy() || !child->CheckAndMarkBusy(true)) return B_BUSY; partition->SetBusy(true); locker.Unlock(); // delete the child error = diskSystem->DeleteChild(child, DUMMY_JOB_ID); // re-lock and unmark busy locker.Lock(); partition->SetBusy(false); child->UnmarkBusy(true); if (error != B_OK) return error; // return change counter return copy_to_user_value(_changeCounter, partition->ChangeCounter()); }
status_t _user_create_child_partition(partition_id partitionID, int32* _changeCounter, off_t offset, off_t size, const char* _type, const char* _name, const char* _parameters, partition_id* childID, int32* childChangeCounter) { // copy parameters in UserStringParameter<false> type; UserStringParameter<true> name; UserStringParameter<true> parameters; int32 changeCounter; status_t error = type.Init(_type, B_DISK_DEVICE_TYPE_LENGTH); if (error == B_OK) error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH); if (error == B_OK) error = parameters.Init(_parameters, B_DISK_DEVICE_MAX_PARAMETER_SIZE); if (error == B_OK) error = copy_from_user_value(changeCounter, _changeCounter); if (error != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // check change counter if (changeCounter != partition->ChangeCounter()) return B_BAD_VALUE; // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (diskSystem == NULL) return B_BAD_VALUE; // mark the partition busy and unlock if (!partition->CheckAndMarkBusy(false)) return B_BUSY; locker.Unlock(); // create the child KPartition *child = NULL; error = diskSystem->CreateChild(partition, offset, size, type.value, name.value, parameters.value, DUMMY_JOB_ID, &child, -1); // re-lock and unmark busy locker.Lock(); partition->UnmarkBusy(false); if (error != B_OK) return error; if (child == NULL) return B_ERROR; child->UnmarkBusy(true); // return change counter and child ID error = copy_to_user_value(_changeCounter, partition->ChangeCounter()); if (error == B_OK) error = copy_to_user_value(childID, child->ID()); return error; }
status_t _user_uninitialize_partition(partition_id partitionID, int32* _changeCounter, partition_id parentID, int32* _parentChangeCounter) { // copy parameters in int32 changeCounter; int32 parentChangeCounter; bool haveParent = parentID >= 0; status_t error = copy_from_user_value(changeCounter, _changeCounter); if (haveParent && error == B_OK) error = copy_from_user_value(parentChangeCounter, _parentChangeCounter); if (error != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // register parent KPartition* parent = NULL; if (haveParent) parent = manager->RegisterPartition(parentID); PartitionRegistrar registrar3(parent, true); // check change counter if (changeCounter != partition->ChangeCounter()) return B_BAD_VALUE; if (haveParent && parentChangeCounter != parent->ChangeCounter()) return B_BAD_VALUE; // the partition must be initialized if (partition->DiskSystem() == NULL) return B_BAD_VALUE; // check busy if (!partition->CheckAndMarkBusy(true)) return B_BUSY; if (partition->IsMounted() || partition->IsChildMounted()) return B_BAD_VALUE; KDiskSystem* diskSystem = partition->DiskSystem(); locker.Unlock(); // Let the disk system uninitialize the partition. This operation is not // mandatory. If implemented, it will destroy the on-disk structures, so // that the disk system cannot accidentally identify the partition later on. if (diskSystem != NULL) diskSystem->Uninitialize(partition, DUMMY_JOB_ID); // re-lock and uninitialize the partition object locker.Lock(); error = partition->UninitializeContents(true); partition->UnmarkBusy(true); if (error != B_OK) return error; // return change counter error = copy_to_user_value(_changeCounter, partition->ChangeCounter()); if (haveParent && error == B_OK) error = copy_to_user_value(_parentChangeCounter, parent->ChangeCounter()); return error; }
status_t _user_initialize_partition(partition_id partitionID, int32* _changeCounter, const char* _diskSystemName, const char* _name, const char* _parameters) { // copy parameters in UserStringParameter<false> diskSystemName; UserStringParameter<true> name; UserStringParameter<true> parameters; int32 changeCounter; status_t error = diskSystemName.Init(_diskSystemName, B_DISK_SYSTEM_NAME_LENGTH); if (error == B_OK) error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH); if (error == B_OK) error = parameters.Init(_parameters, B_DISK_DEVICE_MAX_PARAMETER_SIZE); if (error == B_OK) error = copy_from_user_value(changeCounter, _changeCounter); if (error != B_OK) return error; // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (partition == NULL) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // check change counter if (changeCounter != partition->ChangeCounter()) return B_BAD_VALUE; // the partition must be uninitialized if (partition->DiskSystem() != NULL) return B_BAD_VALUE; // load the new disk system KDiskSystem *diskSystem = manager->LoadDiskSystem(diskSystemName.value, true); if (diskSystem == NULL) return B_ENTRY_NOT_FOUND; DiskSystemLoader loader(diskSystem, true); // mark the partition busy and unlock if (!partition->CheckAndMarkBusy(true)) return B_BUSY; locker.Unlock(); // let the disk system initialize the partition error = diskSystem->Initialize(partition, name.value, parameters.value, DUMMY_JOB_ID); // re-lock and unmark busy locker.Lock(); partition->UnmarkBusy(true); if (error != B_OK) return error; // Set the disk system. Re-check whether a disk system is already set on the // partition. Some disk systems just write the on-disk structures and let // the DDM rescan the partition, in which case the disk system will already // be set. In very unfortunate cases the on-disk structure of the previous // disk system has not been destroyed and the previous disk system has a // higher priority than the new one. The old disk system will thus prevail. // Not setting the new disk system will at least prevent that the partition // object gets into an inconsistent state. if (partition->DiskSystem() == NULL) partition->SetDiskSystem(diskSystem); // return change counter return copy_to_user_value(_changeCounter, partition->ChangeCounter()); }
status_t _user_set_partition_name(partition_id partitionID, int32* _changeCounter, partition_id childID, int32* _childChangeCounter, const char* _name) { // copy parameters in UserStringParameter<false> name; int32 changeCounter; int32 childChangeCounter; status_t error; if ((error = name.Init(_name, B_DISK_DEVICE_NAME_LENGTH)) != B_OK || (error = copy_from_user_value(changeCounter, _changeCounter)) != B_OK || (error = copy_from_user_value(childChangeCounter, _childChangeCounter)) != B_OK) { return error; } // get the partition KDiskDeviceManager* manager = KDiskDeviceManager::Default(); KPartition* partition = manager->WriteLockPartition(partitionID); if (!partition) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar1(partition, true); PartitionRegistrar registrar2(partition->Device(), true); DeviceWriteLocker locker(partition->Device(), true); // register child KPartition* child = manager->RegisterPartition(childID); if (!child) return B_ENTRY_NOT_FOUND; PartitionRegistrar registrar3(child, true); // check change counters if (changeCounter != partition->ChangeCounter() || childChangeCounter != child->ChangeCounter()) { return B_BAD_VALUE; } // the partition must be initialized KDiskSystem* diskSystem = partition->DiskSystem(); if (!diskSystem) return B_BAD_VALUE; // child must indeed be a child of partition if (child->Parent() != partition) return B_BAD_VALUE; // mark the partitions busy and unlock if (partition->IsBusy() || child->IsBusy()) return B_BUSY; partition->SetBusy(true); child->SetBusy(true); locker.Unlock(); // set the child name error = diskSystem->SetName(child, name.value, DUMMY_JOB_ID); // re-lock and unmark busy locker.Lock(); partition->SetBusy(false); child->SetBusy(false); if (error != B_OK) return error; // return change counters if ((error = copy_to_user_value(_changeCounter, partition->ChangeCounter())) != B_OK || (error = copy_to_user_value(_childChangeCounter, child->ChangeCounter())) != B_OK) { return error; } return B_OK; }