//---------------------------------------------------------------------- // This software is part of the Haiku distribution and is covered // by the MIT License. //--------------------------------------------------------------------- #include #include #include #include #include #include #include using namespace std; //#define TRACING 1 #if TRACING # define TRACE(x) printf x #else # define TRACE(x) #endif // constructor BPartitioningInfo::BPartitioningInfo() : fPartitionID(-1), fSpaces(NULL), fCount(0), fCapacity(0) { } // destructor BPartitioningInfo::~BPartitioningInfo() { Unset(); } // SetTo status_t BPartitioningInfo::SetTo(off_t offset, off_t size) { TRACE(("%p - BPartitioningInfo::SetTo(offset = %lld, size = %lld)\n", this, offset, size)); fPartitionID = -1; delete[] fSpaces; if (size > 0) { fSpaces = new(nothrow) partitionable_space_data[1]; if (!fSpaces) return B_NO_MEMORY; fCount = 1; fSpaces[0].offset = offset; fSpaces[0].size = size; } else { fSpaces = NULL; fCount = 0; } fCapacity = fCount; return B_OK; } // Unset void BPartitioningInfo::Unset() { delete[] fSpaces; fPartitionID = -1; fSpaces = NULL; fCount = 0; fCapacity = 0; } // ExcludeOccupiedSpace status_t BPartitioningInfo::ExcludeOccupiedSpace(off_t offset, off_t size) { if (size <= 0) return B_OK; TRACE(("%p - BPartitioningInfo::ExcludeOccupiedSpace(offset = %lld, " "size = %lld)\n", this, offset, size)); int32 leftIndex = -1; int32 rightIndex = -1; for (int32 i = 0; i < fCount; i++) { if (leftIndex == -1 && offset < fSpaces[i].offset + fSpaces[i].size) { leftIndex = i; } if (fSpaces[i].offset < offset + size) rightIndex = i; } TRACE((" leftIndex = %ld, rightIndex = %ld\n", leftIndex, rightIndex)); // If there's no intersection with any free space, we're done. if (leftIndex == -1 || rightIndex == -1 || leftIndex > rightIndex) return B_OK; partitionable_space_data& leftSpace = fSpaces[leftIndex]; partitionable_space_data& rightSpace = fSpaces[rightIndex]; off_t rightSpaceEnd = rightSpace.offset + rightSpace.size; // special case: split a single space in two if (leftIndex == rightIndex && leftSpace.offset < offset && rightSpaceEnd > offset + size) { TRACE((" splitting space at %ld\n", leftIndex)); // add a space after this one status_t error = _InsertSpaces(leftIndex + 1, 1); if (error != B_OK) return error; // IMPORTANT: after calling _InsertSpace(), one can not // use the partitionable_space_data references "leftSpace" // and "rightSpace" anymore (declared above)! partitionable_space_data& space = fSpaces[leftIndex]; partitionable_space_data& newSpace = fSpaces[leftIndex + 1]; space.size = offset - space.offset; newSpace.offset = offset + size; newSpace.size = rightSpaceEnd - newSpace.offset; #ifdef TRACING PrintToStream(); #endif return B_OK; } // check whether the first affected space is eaten completely int32 deleteFirst = leftIndex; if (leftSpace.offset < offset) { leftSpace.size = offset - leftSpace.offset; TRACE((" left space remains, new size is %lld\n", leftSpace.size)); deleteFirst++; } // check whether the last affected space is eaten completely int32 deleteLast = rightIndex; if (rightSpaceEnd > offset + size) { rightSpace.offset = offset + size; rightSpace.size = rightSpaceEnd - rightSpace.offset; TRACE((" right space remains, new offset = %lld, size = %lld\n", rightSpace.offset, rightSpace.size)); deleteLast--; } // remove all spaces that are completely eaten if (deleteFirst <= deleteLast) _RemoveSpaces(deleteFirst, deleteLast - deleteFirst + 1); #ifdef TRACING PrintToStream(); #endif return B_OK; } // PartitionID partition_id BPartitioningInfo::PartitionID() const { return fPartitionID; } // GetPartitionableSpaceAt status_t BPartitioningInfo::GetPartitionableSpaceAt(int32 index, off_t* offset, off_t *size) const { if (!fSpaces) return B_NO_INIT; if (!offset || !size) return B_BAD_VALUE; if (index < 0 || index >= fCount) return B_BAD_INDEX; *offset = fSpaces[index].offset; *size = fSpaces[index].size; return B_OK; } // CountPartitionableSpaces int32 BPartitioningInfo::CountPartitionableSpaces() const { return fCount; } // PrintToStream void BPartitioningInfo::PrintToStream() const { if (!fSpaces) { printf("BPartitioningInfo is not initialized\n"); return; } printf("BPartitioningInfo has %" B_PRId32 " spaces:\n", fCount); for (int32 i = 0; i < fCount; i++) { printf(" space at %" B_PRId32 ": offset = %" B_PRId64 ", size = %" B_PRId64 "\n", i, fSpaces[i].offset, fSpaces[i].size); } } // #pragma mark - // _InsertSpaces status_t BPartitioningInfo::_InsertSpaces(int32 index, int32 count) { if (index <= 0 || index > fCount || count <= 0) return B_BAD_VALUE; // If the capacity is sufficient, we just need to copy the spaces to create // a gap. if (fCount + count <= fCapacity) { memmove(fSpaces + index + count, fSpaces + index, (fCount - index) * sizeof(partitionable_space_data)); fCount += count; return B_OK; } // alloc new array int32 capacity = (fCount + count) * 2; // add a bit room for further resizing partitionable_space_data* spaces = new(nothrow) partitionable_space_data[capacity]; if (!spaces) return B_NO_MEMORY; // copy items memcpy(spaces, fSpaces, index * sizeof(partitionable_space_data)); memcpy(spaces + index + count, fSpaces + index, (fCount - index) * sizeof(partitionable_space_data)); delete[] fSpaces; fSpaces = spaces; fCapacity = capacity; fCount += count; return B_OK; } // _RemoveSpaces void BPartitioningInfo::_RemoveSpaces(int32 index, int32 count) { if (index < 0 || count <= 0 || index + count > fCount) return; if (count < fCount) { int32 endIndex = index + count; memmove(fSpaces + index, fSpaces + endIndex, (fCount - endIndex) * sizeof(partitionable_space_data)); } fCount -= count; }