status_t Header::Write(int fd) { // Try to write the protective MBR PartitionMap partitionMap; PrimaryPartition *partition = NULL; uint32 index = 0; while ((partition = partitionMap.PrimaryPartitionAt(index)) != NULL) { if (index == 0) { uint64 deviceSize = fHeader.AlternateBlock() * fBlockSize; partition->SetTo(fBlockSize, deviceSize, 0xEE, false, fBlockSize); } else partition->Unset(); ++index; } PartitionMapWriter writer(fd, fBlockSize); writer.WriteMBR(&partitionMap, true); // We also write the bootcode, so we can boot GPT disks from BIOS status_t status = _Write(fd, fHeader.EntriesBlock() * fBlockSize, fEntries, _EntryArraySize()); if (status != B_OK) return status; // First write the header, so that we have at least one completely correct // data set status = _WriteHeader(fd); // Write backup entries status_t backupStatus = _Write(fd, fBackupHeader.EntriesBlock() * fBlockSize, fEntries, _EntryArraySize()); return status == B_OK ? backupStatus : status; }
void LogicalPartition::GetPartitionDescriptor(partition_descriptor* descriptor, bool inner) const { PrimaryPartition* primary = GetPrimaryPartition(); if (inner) { descriptor->start = (PartitionTableOffset() - primary->Offset()) / BlockSize(); descriptor->type = primary->Type(); } else { descriptor->start = (Offset() - PartitionTableOffset()) / BlockSize(); descriptor->type = Type(); } descriptor->size = Size() / BlockSize(); descriptor->active = 0x00; descriptor->begin.Unset(); descriptor->end.Unset(); }
// _ParsePrimary status_t PartitionMapParser::_ParsePrimary(const partition_table* table, bool& hadToReFitSize) { if (table == NULL) return B_BAD_VALUE; // check the signature if (table->signature != kPartitionTableSectorSignature) { TRACE(("intel: _ParsePrimary(): invalid PartitionTable signature: %lx\n", (uint32)table->signature)); return B_BAD_DATA; } hadToReFitSize = false; // examine the table for (int32 i = 0; i < 4; i++) { const partition_descriptor* descriptor = &table->table[i]; PrimaryPartition* partition = fMap->PrimaryPartitionAt(i); partition->SetTo(descriptor, 0, fBlockSize); // work-around potential BIOS/OS problems hadToReFitSize |= partition->FitSizeToSession(fSessionSize); // ignore, if location is bad if (!partition->CheckLocation(fSessionSize)) { TRACE(("intel: _ParsePrimary(): partition %ld: bad location, " "ignoring\n", i)); partition->Unset(); } } // allocate a partition_table buffer fPartitionTable = new(nothrow) partition_table; if (fPartitionTable == NULL) return B_NO_MEMORY; // parse extended partitions status_t error = B_OK; for (int32 i = 0; error == B_OK && i < 4; i++) { PrimaryPartition* primary = fMap->PrimaryPartitionAt(i); if (primary->IsExtended()) error = _ParseExtended(primary, primary->Offset()); } // cleanup delete fPartitionTable; fPartitionTable = NULL; return error; }
status_t PartitionMapHandle::Init() { // initialize the partition map from the mutable partition BMutablePartition* partition = Partition(); int32 count = partition->CountChildren(); if (count > 4) return B_BAD_VALUE; int32 extendedCount = 0; for (int32 i = 0; i < count; i++) { BMutablePartition* child = partition->ChildAt(i); PartitionType type; if (!type.SetType(child->Type())) return B_BAD_VALUE; // only one extended partition is allowed if (type.IsExtended()) { if (++extendedCount > 1) return B_BAD_VALUE; } // TODO: Get these from the parameters. int32 index = i; bool active = false; PrimaryPartition* primary = fPartitionMap.PrimaryPartitionAt(index); primary->SetTo(child->Offset(), child->Size(), type.Type(), active, partition->BlockSize()); child->SetChildCookie(primary); } // The extended partition (if any) is initialized by // ExtendedPartitionHandle::Init(). return B_OK; }
status_t PartitionMapHandle::GetPartitioningInfo(BPartitioningInfo* info) { // init to the full size (minus the first sector) off_t size = Partition()->ContentSize(); status_t error = info->SetTo(Partition()->BlockSize(), size - Partition()->BlockSize()); if (error != B_OK) return error; // exclude the space of the existing partitions for (int32 i = 0; i < 4; i++) { PrimaryPartition* primary = fPartitionMap.PrimaryPartitionAt(i); if (!primary->IsEmpty()) { error = info->ExcludeOccupiedSpace(primary->Offset(), primary->Size()); if (error != B_OK) return error; } } return B_OK; }
status_t PrimaryPartition::Assign(const PrimaryPartition& other) { partition_descriptor descriptor; other.GetPartitionDescriptor(&descriptor); SetTo(&descriptor, 0, other.BlockSize()); const LogicalPartition* otherLogical = other.fHead; while (otherLogical) { off_t tableOffset = otherLogical->PartitionTableOffset(); otherLogical->GetPartitionDescriptor(&descriptor); LogicalPartition* logical = new(nothrow) LogicalPartition( &descriptor, tableOffset, this); if (!logical) return B_NO_MEMORY; AddLogicalPartition(logical); otherLogical = otherLogical->Next(); } return B_OK; }
// ep_scan_partition static status_t ep_scan_partition(int fd, partition_data* partition, void* cookie) { // check parameters if (fd < 0 || !partition || !partition->cookie) return B_ERROR; TRACE(("intel: ep_scan_partition(%d, %lld, %lld, %ld)\n", fd, partition->offset, partition->size, partition->block_size)); partition_data* parent = get_parent_partition(partition->id); if (!parent) return B_ERROR; PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; // fill in the partition_data structure partition->status = B_PARTITION_VALID; partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; partition->content_size = partition->size; // (no content_name and content_parameters) // (content_type is set by the system) partition->content_cookie = primary; // children status_t error = B_OK; int32 index = 0; for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) { LogicalPartition* logical = primary->LogicalPartitionAt(i); partition_data* child = create_child_partition(partition->id, index, parent->offset + logical->Offset(), logical->Size(), -1); index++; if (!child) { // something went wrong TRACE(("intel: ep_scan_partition(): failed to create child " "partition\n")); error = B_ERROR; break; } child->block_size = partition->block_size; // (no name) char type[B_FILE_NAME_LENGTH]; logical->GetTypeString(type); child->type = strdup(type); // parameters char buffer[128]; sprintf(buffer, "active %s ;\npartition_table_offset %lld ;\n", logical->Active() ? "true" : "false", logical->PartitionTableOffset()); child->parameters = strdup(buffer); child->cookie = logical; // check for allocation problems if (!child->type || !child->parameters) { TRACE(("intel: ep_scan_partition(): failed to allocation type " "or parameters\n")); error = B_NO_MEMORY; break; } } // cleanup on error if (error != B_OK) { partition->content_cookie = NULL; for (int32 i = 0; i < partition->child_count; i++) { if (partition_data* child = get_child_partition(partition->id, i)) child->cookie = NULL; } } return error; }
// pm_scan_partition static status_t pm_scan_partition(int fd, partition_data* partition, void* cookie) { // check parameters if (fd < 0 || !partition || !cookie) return B_ERROR; TRACE(("intel: pm_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd, partition->id, partition->offset, partition->size, partition->block_size)); PartitionMapCookie* map = (PartitionMapCookie*)cookie; // fill in the partition_data structure partition->status = B_PARTITION_VALID; partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; partition->content_size = partition->size; // (no content_name and content_parameters) // (content_type is set by the system) partition->content_cookie = map; // children status_t error = B_OK; int32 index = 0; for (int32 i = 0; i < 4; i++) { PrimaryPartition* primary = map->PrimaryPartitionAt(i); if (!primary->IsEmpty()) { partition_data* child = create_child_partition(partition->id, index, partition->offset + primary->Offset(), primary->Size(), -1); index++; if (!child) { // something went wrong error = B_ERROR; break; } child->block_size = partition->block_size; // (no name) char type[B_FILE_NAME_LENGTH]; primary->GetTypeString(type); child->type = strdup(type); // parameters char buffer[128]; sprintf(buffer, "type = %u ; active = %d", primary->Type(), primary->Active()); child->parameters = strdup(buffer); child->cookie = primary; // check for allocation problems if (!child->type || !child->parameters) { error = B_NO_MEMORY; break; } } } // keep map on success or cleanup on error if (error == B_OK) { atomic_add(&map->ref_count, 1); } else { partition->content_cookie = NULL; for (int32 i = 0; i < partition->child_count; i++) { if (partition_data* child = get_child_partition(partition->id, i)) child->cookie = NULL; } } return error; }
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; }