#include <stdio.h>
#include <string.h>
#include <new>
#include <disk_device_manager.h>
#include <PartitioningInfo.h>
#include <syscalls.h>
#include <ddm_userland_interface_defs.h>
using namespace std;
#if TRACING
# define TRACE(x) printf x
#else
# define TRACE(x)
#endif
BPartitioningInfo::BPartitioningInfo()
:
fPartitionID(-1),
fSpaces(NULL),
fCount(0),
fCapacity(0)
{
}
BPartitioningInfo::~BPartitioningInfo()
{
Unset();
}
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;
}
void
BPartitioningInfo::Unset()
{
delete[] fSpaces;
fPartitionID = -1;
fSpaces = NULL;
fCount = 0;
fCapacity = 0;
}
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 (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;
if (leftIndex == rightIndex && leftSpace.offset < offset
&& rightSpaceEnd > offset + size) {
TRACE((" splitting space at %ld\n", leftIndex));
status_t error = _InsertSpaces(leftIndex + 1, 1);
if (error != B_OK)
return error;
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;
}
int32 deleteFirst = leftIndex;
if (leftSpace.offset < offset) {
leftSpace.size = offset - leftSpace.offset;
TRACE((" left space remains, new size is %lld\n", leftSpace.size));
deleteFirst++;
}
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--;
}
if (deleteFirst <= deleteLast)
_RemoveSpaces(deleteFirst, deleteLast - deleteFirst + 1);
#ifdef TRACING
PrintToStream();
#endif
return B_OK;
}
partition_id
BPartitioningInfo::PartitionID() const
{
return fPartitionID;
}
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;
}
int32
BPartitioningInfo::CountPartitionableSpaces() const
{
return fCount;
}
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);
}
}
status_t
BPartitioningInfo::_InsertSpaces(int32 index, int32 count)
{
if (index <= 0 || index > fCount || count <= 0)
return B_BAD_VALUE;
if (fCount + count <= fCapacity) {
memmove(fSpaces + index + count, fSpaces + index,
(fCount - index) * sizeof(partitionable_space_data));
fCount += count;
return B_OK;
}
int32 capacity = (fCount + count) * 2;
partitionable_space_data* spaces
= new(nothrow) partitionable_space_data[capacity];
if (!spaces)
return B_NO_MEMORY;
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;
}
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;
}