void _AddSpaces(BPartition* partition, PartitionView* parentView) { // add any available space on the partition BPartitioningInfo info; if (partition->GetPartitioningInfo(&info) >= B_OK) { off_t parentSize = partition->Size(); off_t offset; off_t size; for (int32 i = 0; info.GetPartitionableSpaceAt(i, &offset, &size) >= B_OK; i++) { // TODO: remove again once Disk Device API is fixed if (!is_valid_partitionable_space(size)) continue; // double scale = (double)size / parentSize; partition_id id = fSpaceIDMap.SpaceIDFor(partition->ID(), offset); PartitionView* view = new PartitionView(B_TRANSLATE("<empty>"), scale, offset, parentView->Level() + 1, id); fViewMap.Put(id, view); BGroupLayout* layout = parentView->GroupLayout(); layout->AddView(_FindInsertIndex(view, layout), view, scale); } } }
uint32 ExtendedPartitionHandle::SupportedOperations(uint32 mask) { uint32 flags = 0; // creating child if ((mask & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) != 0) { BPartitioningInfo info; if (GetPartitioningInfo(&info) == B_OK && info.CountPartitionableSpaces() > 1) { flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; } } return flags; }
uint32 GPTPartitionHandle::SupportedOperations(uint32 mask) { uint32 flags = B_DISK_SYSTEM_SUPPORTS_RESIZING | B_DISK_SYSTEM_SUPPORTS_MOVING | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS | B_DISK_SYSTEM_SUPPORTS_INITIALIZING; // creating child if ((mask & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) != 0) { BPartitioningInfo info; if (GetPartitioningInfo(&info) == B_OK && info.CountPartitionableSpaces() > 1) { flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; } } return flags; }
void _AddPartition(BPartition* partition) const { // add the partition itself fPartitionList->AddPartition(partition); // add any available space on it BPartitioningInfo info; status_t ret = partition->GetPartitioningInfo(&info); if (ret >= B_OK) { partition_id parentID = partition->ID(); off_t offset; off_t size; for (int32 i = 0; info.GetPartitionableSpaceAt(i, &offset, &size) >= B_OK; i++) { // TODO: remove again once Disk Device API is fixed if (!is_valid_partitionable_space(size)) continue; // partition_id id = fSpaceIDMap.SpaceIDFor(parentID, offset); fPartitionList->AddSpace(parentID, id, offset, size); } } }
void _NewPartition() { if (!fPrepared) { if (fDevice->IsReadOnly()) printf("Device is read-only!\n"); else printf("Sorry, not prepared for modifications!\n"); return; } // get the parent partition BPartition* partition = NULL; int32 partitionIndex; if (!_SelectPartition("parent partition index [-1 to abort]: ", partition, partitionIndex)) { return; } printf("\nselected partition:\n\n"); print_partition_table_header(); print_partition(partition, 0, partitionIndex); if (!partition->ContainsPartitioningSystem()) { printf("The selected partition does not contain a partitioning " "system.\n"); return; } // get supported types BObjectList<BString> supportedTypes(20, true); BString typeBuffer; int32 cookie = 0; while (partition->GetNextSupportedChildType(&cookie, &typeBuffer) == B_OK) { supportedTypes.AddItem(new BString(typeBuffer)); } if (supportedTypes.IsEmpty()) { printf("The partitioning system is not able to create any " "child partition (no supported types).\n"); return; } // get partitioning info BPartitioningInfo partitioningInfo; status_t error = partition->GetPartitioningInfo(&partitioningInfo); if (error != B_OK) { printf("Failed to get partitioning info for partition: %s\n", strerror(error)); return; } int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); if (spacesCount == 0) { printf("There's no space on the partition where a child partition " "could be created\n"); return; } // let the user select the partition type, if there's more than one int64 typeIndex = 0; int32 supportedTypesCount = supportedTypes.CountItems(); if (supportedTypesCount > 1) { // list them printf("Possible partition types:\n"); for (int32 i = 0; i < supportedTypesCount; i++) printf("%2ld %s\n", i, supportedTypes.ItemAt(i)->String()); if (!_ReadNumber("supported type index [-1 to abort]: ", 0, supportedTypesCount - 1, -1, "invalid index", typeIndex)) { return; } } const char* type = supportedTypes.ItemAt(typeIndex)->String(); // list partitionable spaces printf("Unused regions where the new partition could be created:\n"); for (int32 i = 0; i < spacesCount; i++) { off_t _offset; off_t _size; partitioningInfo.GetPartitionableSpaceAt(i, &_offset, &_size); BString offset, size; get_size_string(_offset, offset); get_size_string(_size, size); printf("%2ld start: %8s, size: %8s\n", i, offset.String(), size.String()); } // let the user select the partitionable space, if there's more than one int64 spaceIndex = 0; if (spacesCount > 1) { if (!_ReadNumber("unused region index [-1 to abort]: ", 0, spacesCount - 1, -1, "invalid index", spaceIndex)) { return; } } off_t spaceOffset; off_t spaceSize; partitioningInfo.GetPartitionableSpaceAt(spaceIndex, &spaceOffset, &spaceSize); off_t start; off_t size; BString parameters; while (true) { // let the user enter start, size, and parameters // start while (true) { BString spaceOffsetString; get_size_string(spaceOffset, spaceOffsetString); BString prompt("partition start [default: "); prompt << spaceOffsetString << "]: "; if (!_ReadSize(prompt.String(), spaceOffset, start)) return; if (start >= spaceOffset && start <= spaceOffset + spaceSize) break; printf("invalid partition start\n"); } // size off_t maxSize = spaceOffset + spaceSize - start; while (true) { BString maxSizeString; get_size_string(maxSize, maxSizeString); BString prompt("partition size [default: "); prompt << maxSizeString << "]: "; if (!_ReadSize(prompt.String(), maxSize, size)) return; if (size >= 0 && start + size <= spaceOffset + spaceSize) break; printf("invalid partition size\n"); } // parameters if (!_ReadLine("partition parameters: ", parameters)) return; // validate parameters off_t validatedStart = start; off_t validatedSize = size; // TODO: Support the name parameter! if (partition->ValidateCreateChild(&start, &size, type, NULL, parameters.String()) != B_OK) { printf("Validation of the given values failed. Sorry, can't " "continue.\n"); return; } // did the disk system change offset or size? if (validatedStart == start && validatedSize == size) { printf("Everything looks dandy.\n"); } else { BString startString, sizeString; get_size_string(validatedStart, startString); get_size_string(validatedSize, sizeString); printf("The disk system adjusted the partition start and " "size to %lld (%s) and %lld (%s).\n", validatedStart, startString.String(), validatedSize, sizeString.String()); start = validatedStart; size = validatedSize; } // let the user decide whether to continue, change parameters, or // abort bool changeParameters = false; while (true) { BString line; _ReadLine("[c]ontinue, change [p]arameters, or [a]bort? ", line); if (line == "a") return; if (line == "p") { changeParameters = true; break; } if (line == "c") break; printf("invalid input\n"); } if (!changeParameters) break; } // create child error = partition->CreateChild(start, size, type, NULL, parameters.String()); if (error != B_OK) printf("Creating the partition failed: %s\n", strerror(error)); }
status_t ExtendedPartitionHandle::CreateChild(off_t offset, off_t size, const char* typeString, const char* name, const char* _parameters, BMutablePartition** _child) { // check type PartitionType type; if (!type.SetType(typeString) || type.IsEmpty()) return B_BAD_VALUE; // check name if (name != NULL && name[0] != '\0') return B_BAD_VALUE; // offset properly aligned? if (offset != sector_align(offset, Partition()->BlockSize()) || size != sector_align(size, Partition()->BlockSize())) return B_BAD_VALUE; // check the free space situation BPartitioningInfo info; status_t error = GetPartitioningInfo(&info); if (error != B_OK) return error; bool foundSpace = false; off_t end = offset + size; int32 spacesCount = info.CountPartitionableSpaces(); for (int32 i = 0; i < spacesCount; i++) { off_t spaceOffset, spaceSize; info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize); off_t spaceEnd = spaceOffset + spaceSize; if (offset >= spaceOffset && end <= spaceEnd) { foundSpace = true; break; } } if (!foundSpace) return B_BAD_VALUE; BString parameters(_parameters); parameters << "partition_table_offset " << offset - PTS_OFFSET << " ;\n"; // everything looks good, create the child BMutablePartition* child; error = Partition()->CreateChild(-1, typeString, NULL, parameters.String(), &child); if (error != B_OK) return error; // init the child child->SetOffset(offset); child->SetSize(size); child->SetBlockSize(Partition()->BlockSize()); //child->SetFlags(0); child->SetChildCookie(Partition()); *_child = child; return B_OK; }
status_t ExtendedPartitionHandle::ValidateCreateChild(off_t* _offset, off_t* _size, const char* typeString, BString* name, const char* parameters) { // check type if (!typeString) return B_BAD_VALUE; // check name if (name) name->Truncate(0); // check the free space situation BPartitioningInfo info; status_t error = GetPartitioningInfo(&info); if (error != B_OK) return error; // any space in the partition at all? int32 spacesCount = info.CountPartitionableSpaces(); if (spacesCount == 0) return B_BAD_VALUE; // check offset and size off_t offset = sector_align(*_offset, Partition()->BlockSize()); off_t size = sector_align(*_size, Partition()->BlockSize()); // TODO: Rather round size up? off_t end = offset + size; // get the first partitionable space the requested interval intersects with int32 spaceIndex = -1; int32 closestSpaceIndex = -1; off_t closestSpaceDistance = 0; for (int32 i = 0; i < spacesCount; i++) { off_t spaceOffset, spaceSize; info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize); off_t spaceEnd = spaceOffset + spaceSize; if ((spaceOffset >= offset && spaceOffset < end) || (offset >= spaceOffset && offset < spaceEnd)) { spaceIndex = i; break; } off_t distance; if (offset < spaceOffset) distance = spaceOffset - end; else distance = spaceEnd - offset; if (closestSpaceIndex == -1 || distance < closestSpaceDistance) { closestSpaceIndex = i; closestSpaceDistance = distance; } } // get the space we found off_t spaceOffset, spaceSize; info.GetPartitionableSpaceAt( spaceIndex >= 0 ? spaceIndex : closestSpaceIndex, &spaceOffset, &spaceSize); off_t spaceEnd = spaceOffset + spaceSize; // If the requested intervald doesn't intersect with any space yet, move // it, so that it does. if (spaceIndex < 0) { spaceIndex = closestSpaceIndex; if (offset < spaceOffset) { offset = spaceOffset; end = offset + size; } else { end = spaceEnd; offset = end - size; } } // move/shrink the interval, so that it fully lies within the space if (offset < spaceOffset) { offset = spaceOffset; end = offset + size; if (end > spaceEnd) { end = spaceEnd; size = end - offset; } } else if (end > spaceEnd) { end = spaceEnd; offset = end - size; if (offset < spaceOffset) { offset = spaceOffset; size = end - offset; } } *_offset = offset; *_size = size; return B_OK; }
status_t PartitionMapHandle::CreateChild(off_t offset, off_t size, const char* typeString, const char* name, const char* parameters, BMutablePartition** _child) { // check type PartitionType type; if (!type.SetType(typeString) || type.IsEmpty()) return B_BAD_VALUE; if (type.IsExtended() && fPartitionMap.ExtendedPartitionIndex() >= 0) return B_BAD_VALUE; // check name if (name && *name != '\0') return B_BAD_VALUE; // check parameters void* handle = parse_driver_settings_string(parameters); if (handle == NULL) return B_ERROR; bool active = get_driver_boolean_parameter(handle, "active", false, true); delete_driver_settings(handle); // get a spare primary partition PrimaryPartition* primary = NULL; for (int32 i = 0; i < 4; i++) { if (fPartitionMap.PrimaryPartitionAt(i)->IsEmpty()) { primary = fPartitionMap.PrimaryPartitionAt(i); break; } } if (!primary) return B_BAD_VALUE; // offset properly aligned? if (offset != sector_align(offset, Partition()->BlockSize()) || size != sector_align(size, Partition()->BlockSize())) return B_BAD_VALUE; // check the free space situation BPartitioningInfo info; status_t error = GetPartitioningInfo(&info); if (error != B_OK) return error; bool foundSpace = false; off_t end = offset + size; int32 spacesCount = info.CountPartitionableSpaces(); for (int32 i = 0; i < spacesCount; i++) { off_t spaceOffset, spaceSize; info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize); off_t spaceEnd = spaceOffset + spaceSize; if (offset >= spaceOffset && end <= spaceEnd) { foundSpace = true; break; } } if (!foundSpace) return B_BAD_VALUE; // create the child // (Note: the primary partition index is indeed the child index, since // we picked the first empty primary partition.) BMutablePartition* partition = Partition(); BMutablePartition* child; error = partition->CreateChild(primary->Index(), typeString, name, parameters, &child); if (error != B_OK) return error; // init the child child->SetOffset(offset); child->SetSize(size); child->SetBlockSize(partition->BlockSize()); //child->SetFlags(0); child->SetChildCookie(primary); // init the primary partition primary->SetTo(offset, size, type.Type(), active, partition->BlockSize()); *_child = child; return B_OK; }
status_t PartitionMapHandle::ValidateCreateChild(off_t* _offset, off_t* _size, const char* typeString, BString* name, const char* parameters) { // check type PartitionType type; if (!type.SetType(typeString) || type.IsEmpty()) return B_BAD_VALUE; if (type.IsExtended() && fPartitionMap.ExtendedPartitionIndex() >= 0) { // There can only be a single extended partition return B_BAD_VALUE; } // check name if (name) name->Truncate(0); // check parameters void* handle = parse_driver_settings_string(parameters); if (handle == NULL) return B_ERROR; get_driver_boolean_parameter(handle, "active", false, true); delete_driver_settings(handle); // do we have a spare primary partition? if (fPartitionMap.CountNonEmptyPrimaryPartitions() == 4) return B_BAD_VALUE; // check the free space situation BPartitioningInfo info; status_t error = GetPartitioningInfo(&info); if (error != B_OK) return error; // any space in the partition at all? int32 spacesCount = info.CountPartitionableSpaces(); if (spacesCount == 0) return B_BAD_VALUE; // check offset and size off_t offset = sector_align(*_offset, Partition()->BlockSize()); off_t size = sector_align(*_size, Partition()->BlockSize()); // TODO: Rather round size up? off_t end = offset + size; // get the first partitionable space the requested interval intersects with int32 spaceIndex = -1; int32 closestSpaceIndex = -1; off_t closestSpaceDistance = 0; for (int32 i = 0; i < spacesCount; i++) { off_t spaceOffset, spaceSize; info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize); off_t spaceEnd = spaceOffset + spaceSize; if ((spaceOffset >= offset && spaceOffset < end) || (offset >= spaceOffset && offset < spaceEnd)) { spaceIndex = i; break; } off_t distance; if (offset < spaceOffset) distance = spaceOffset - end; else distance = spaceEnd - offset; if (closestSpaceIndex == -1 || distance < closestSpaceDistance) { closestSpaceIndex = i; closestSpaceDistance = distance; } } // get the space we found off_t spaceOffset, spaceSize; info.GetPartitionableSpaceAt( spaceIndex >= 0 ? spaceIndex : closestSpaceIndex, &spaceOffset, &spaceSize); off_t spaceEnd = spaceOffset + spaceSize; // If the requested intervald doesn't intersect with any space yet, move // it, so that it does. if (spaceIndex < 0) { spaceIndex = closestSpaceIndex; if (offset < spaceOffset) { offset = spaceOffset; end = offset + size; } else { end = spaceEnd; offset = end - size; } } // move/shrink the interval, so that it fully lies within the space if (offset < spaceOffset) { offset = spaceOffset; end = offset + size; if (end > spaceEnd) { end = spaceEnd; size = end - offset; } } else if (end > spaceEnd) { end = spaceEnd; offset = end - size; if (offset < spaceOffset) { offset = spaceOffset; size = end - offset; } } *_offset = offset; *_size = size; return B_OK; }
void MainWindow::_Create(BDiskDevice* disk, partition_id selectedPartition) { if (!disk || selectedPartition > -2) { _DisplayPartitionError(B_TRANSLATE("The currently selected partition " "is not empty.")); return; } if (disk->IsReadOnly()) { _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); return; } PartitionListRow* currentSelection = dynamic_cast<PartitionListRow*>( fListView->CurrentSelection()); if (!currentSelection) { _DisplayPartitionError(B_TRANSLATE("There was an error acquiring the " "partition row.")); return; } BPartition* parent = disk->FindDescendant(currentSelection->ParentID()); if (!parent) { _DisplayPartitionError(B_TRANSLATE("The currently selected partition " "does not have a parent partition.")); return; } if (!parent->ContainsPartitioningSystem()) { _DisplayPartitionError(B_TRANSLATE("The selected partition does not " "contain a partitioning system.")); return; } ModificationPreparer modificationPreparer(disk); status_t ret = modificationPreparer.ModificationStatus(); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " "disk for modifications."), NULL, ret); return; } // get partitioning info BPartitioningInfo partitioningInfo; status_t error = parent->GetPartitioningInfo(&partitioningInfo); if (error != B_OK) { _DisplayPartitionError(B_TRANSLATE("Could not aquire partitioning " "information.")); return; } int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); if (spacesCount == 0) { _DisplayPartitionError(B_TRANSLATE("There's no space on the partition " "where a child partition could be created.")); return; } BString name, type, parameters; off_t offset = currentSelection->Offset(); off_t size = currentSelection->Size(); CreateParamsPanel* panel = new CreateParamsPanel(this, parent, offset, size); if (panel->Go(offset, size, name, type, parameters) == GO_CANCELED) return; ret = parent->ValidateCreateChild(&offset, &size, type.String(), &name, parameters.String()); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Validation of the given creation " "parameters failed.")); return; } // Warn the user one more time... BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " "want to write the changes back to disk now?\n\n" "All data on the partition will be irretrievably lost if you do " "so!"), B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); int32 choice = alert->Go(); if (choice == 1) return; ret = parent->CreateChild(offset, size, type.String(), name.String(), parameters.String()); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Creation of the partition has " "failed.")); return; } // commit ret = modificationPreparer.CommitModifications(); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Failed to format the " "partition. No changes have been written to disk.")); return; } // The disk layout has changed, update disk information bool updated; ret = disk->Update(&updated); _ScanDrives(); fDiskView->ForceUpdate(); }