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 // _SetTo 174 status_t 175 BPartitioningInfo::_SetTo(partition_id partition, int32 changeCounter) 176 { 177 Unset(); 178 179 status_t error = B_OK; 180 partitionable_space_data* buffer = NULL; 181 int32 count = 0; 182 int32 actualCount = 0; 183 while (true) { 184 error = _kern_get_partitionable_spaces(partition, changeCounter, 185 buffer, count, &actualCount); 186 if (error != B_BUFFER_OVERFLOW) 187 break; 188 189 // buffer too small re-allocate it 190 delete[] buffer; 191 buffer = new(nothrow) partitionable_space_data[actualCount]; 192 if (!buffer) { 193 error = B_NO_MEMORY; 194 break; 195 } 196 197 count = actualCount; 198 } 199 200 // set data / cleanup on failure 201 if (error == B_OK) { 202 fPartitionID = partition; 203 fSpaces = buffer; 204 fCount = actualCount; 205 } else if (buffer) 206 delete[] buffer; 207 208 return error; 209 } 210 211 212 // _InsertSpaces 213 status_t 214 BPartitioningInfo::_InsertSpaces(int32 index, int32 count) 215 { 216 if (index <= 0 || index > fCount || count <= 0) 217 return B_BAD_VALUE; 218 219 // If the capacity is sufficient, we just need to copy the spaces to create 220 // a gap. 221 if (fCount + count <= fCapacity) { 222 memmove(fSpaces + index + count, fSpaces + index, fCount - index); 223 fCount += count; 224 return B_OK; 225 } 226 227 // alloc new array 228 int32 capacity = (fCount + count) * 2; 229 // add a bit room for further resizing 230 231 partitionable_space_data* spaces 232 = new(nothrow) partitionable_space_data[capacity]; 233 if (!spaces) 234 return B_NO_MEMORY; 235 236 // copy items 237 memcpy(spaces, fSpaces, index); 238 memcpy(spaces + index + count, fSpaces + index, fCount - index); 239 240 delete[] fSpaces; 241 fSpaces = spaces; 242 fCapacity = capacity; 243 fCount += count; 244 245 return B_OK; 246 } 247 248 249 // _RemoveSpaces 250 void 251 BPartitioningInfo::_RemoveSpaces(int32 index, int32 count) 252 { 253 if (index <= 0 || count <= 0 || index + count > fCount) 254 return; 255 256 if (count < fCount) { 257 int32 endIndex = index + count; 258 memmove(fSpaces + index, fSpaces + endIndex, fCount - endIndex); 259 } 260 261 fCount -= count; 262 } 263