1 //---------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 //--------------------------------------------------------------------- 5 6 #include <string.h> 7 8 #include <new> 9 10 #include <PartitioningInfo.h> 11 12 #include <syscalls.h> 13 #include <disk_device_manager/ddm_userland_interface.h> 14 15 16 using namespace std; 17 18 19 // constructor 20 BPartitioningInfo::BPartitioningInfo() 21 : fPartitionID(-1), 22 fSpaces(NULL), 23 fCount(0), 24 fCapacity(0) 25 { 26 } 27 28 29 // destructor 30 BPartitioningInfo::~BPartitioningInfo() 31 { 32 Unset(); 33 } 34 35 36 // SetTo 37 status_t 38 BPartitioningInfo::SetTo(off_t offset, off_t size) 39 { 40 fPartitionID = -1; 41 delete[] fSpaces; 42 43 if (size > 0) { 44 fSpaces = new(nothrow) partitionable_space_data[1]; 45 if (!fSpaces) 46 return B_NO_MEMORY; 47 48 fCount = 1; 49 fSpaces[0].offset = offset; 50 fSpaces[0].size = size; 51 } else { 52 fSpaces = NULL; 53 fCount = 0; 54 } 55 56 fCapacity = fCount; 57 58 return B_OK; 59 } 60 61 62 // Unset 63 void 64 BPartitioningInfo::Unset() 65 { 66 delete[] fSpaces; 67 fPartitionID = -1; 68 fSpaces = NULL; 69 fCount = 0; 70 fCapacity = 0; 71 } 72 73 74 // ExcludeOccupiedSpace 75 status_t 76 BPartitioningInfo::ExcludeOccupiedSpace(off_t offset, off_t size) 77 { 78 if (size <= 0) 79 return B_OK; 80 81 int32 leftIndex = -1; 82 int32 rightIndex = -1; 83 for (int32 i = 0; i < fCount; i++) { 84 if (leftIndex == -1 85 && offset < fSpaces[i].offset + fSpaces[i].size) { 86 leftIndex = i; 87 } 88 89 if (fSpaces[i].offset < offset + size) 90 rightIndex = i; 91 } 92 93 // If there's no intersection with any free space, we're done. 94 if (leftIndex == -1 || rightIndex == -1 || leftIndex > rightIndex) 95 return B_OK; 96 97 partitionable_space_data& leftSpace = fSpaces[leftIndex]; 98 partitionable_space_data& rightSpace = fSpaces[rightIndex]; 99 100 off_t rightSpaceEnd = rightSpace.offset + rightSpace.size; 101 102 // special case: split a single space in two 103 if (leftIndex == rightIndex && leftSpace.offset < offset 104 && rightSpaceEnd > offset + size) { 105 // add a space after this one 106 status_t error = _InsertSpaces(leftIndex + 1, 1); 107 if (error != B_OK) 108 return error; 109 110 partitionable_space_data& space = fSpaces[leftIndex]; 111 partitionable_space_data& newSpace = fSpaces[leftIndex + 1]; 112 113 space.size = offset - space.offset; 114 115 newSpace.offset = offset + size; 116 newSpace.size = rightSpaceEnd - newSpace.offset; 117 118 return B_OK; 119 } 120 121 // check whether the first affected space is eaten completely 122 int32 deleteFirst = leftIndex; 123 if (leftSpace.offset < offset) { 124 leftSpace.size = offset - leftSpace.offset; 125 deleteFirst++; 126 } 127 128 // check whether the last affected space is eaten completely 129 int32 deleteLast = rightIndex; 130 if (rightSpaceEnd > offset + size) { 131 rightSpace.offset = offset + size; 132 rightSpace.size = rightSpaceEnd - rightSpace.offset; 133 deleteLast--; 134 } 135 136 // remove all spaces that are completely eaten 137 if (deleteFirst <= deleteLast) 138 _RemoveSpaces(deleteFirst, deleteLast - deleteFirst + 1); 139 140 return B_OK; 141 } 142 143 144 // PartitionID 145 partition_id 146 BPartitioningInfo::PartitionID() const 147 { 148 return fPartitionID; 149 } 150 151 152 // GetPartitionableSpaceAt 153 status_t 154 BPartitioningInfo::GetPartitionableSpaceAt(int32 index, off_t *offset, 155 off_t *size) const 156 { 157 if (!fSpaces || !offset || !size || index < 0 || index >= fCount) 158 return B_BAD_VALUE; 159 *offset = fSpaces[index].offset; 160 *size = fSpaces[index].size; 161 return B_OK; 162 } 163 164 165 // CountPartitionableSpaces 166 int32 167 BPartitioningInfo::CountPartitionableSpaces() const 168 { 169 return fCount; 170 } 171 172 173 // _InsertSpaces 174 status_t 175 BPartitioningInfo::_InsertSpaces(int32 index, int32 count) 176 { 177 if (index <= 0 || index > fCount || count <= 0) 178 return B_BAD_VALUE; 179 180 // If the capacity is sufficient, we just need to copy the spaces to create 181 // a gap. 182 if (fCount + count <= fCapacity) { 183 memmove(fSpaces + index + count, fSpaces + index, fCount - index); 184 fCount += count; 185 return B_OK; 186 } 187 188 // alloc new array 189 int32 capacity = (fCount + count) * 2; 190 // add a bit room for further resizing 191 192 partitionable_space_data* spaces 193 = new(nothrow) partitionable_space_data[capacity]; 194 if (!spaces) 195 return B_NO_MEMORY; 196 197 // copy items 198 memcpy(spaces, fSpaces, index); 199 memcpy(spaces + index + count, fSpaces + index, fCount - index); 200 201 delete[] fSpaces; 202 fSpaces = spaces; 203 fCapacity = capacity; 204 fCount += count; 205 206 return B_OK; 207 } 208 209 210 // _RemoveSpaces 211 void 212 BPartitioningInfo::_RemoveSpaces(int32 index, int32 count) 213 { 214 if (index <= 0 || count <= 0 || index + count > fCount) 215 return; 216 217 if (count < fCount) { 218 int32 endIndex = index + count; 219 memmove(fSpaces + index, fSpaces + endIndex, fCount - endIndex); 220 } 221 222 fCount -= count; 223 } 224