1 //---------------------------------------------------------------------- 2 // This software is part of the OpenBeOS distribution and is covered 3 // by the OpenBeOS license. 4 //--------------------------------------------------------------------- 5 6 #include <stdio.h> 7 #include <string.h> 8 9 #include <new> 10 11 #include <disk_device_manager.h> 12 #include <PartitioningInfo.h> 13 14 #include <syscalls.h> 15 #include <ddm_userland_interface_defs.h> 16 17 18 using namespace std; 19 20 21 //#define TRACING 1 22 #if TRACING 23 # define TRACE(x) printf x 24 #else 25 # define TRACE(x) 26 #endif 27 28 29 // constructor 30 BPartitioningInfo::BPartitioningInfo() 31 : fPartitionID(-1), 32 fSpaces(NULL), 33 fCount(0), 34 fCapacity(0) 35 { 36 } 37 38 39 // destructor 40 BPartitioningInfo::~BPartitioningInfo() 41 { 42 Unset(); 43 } 44 45 46 // SetTo 47 status_t 48 BPartitioningInfo::SetTo(off_t offset, off_t size) 49 { 50 TRACE(("%p - BPartitioningInfo::SetTo(offset = %lld, size = %lld)\n", this, offset, size)); 51 52 fPartitionID = -1; 53 delete[] fSpaces; 54 55 if (size > 0) { 56 fSpaces = new(nothrow) partitionable_space_data[1]; 57 if (!fSpaces) 58 return B_NO_MEMORY; 59 60 fCount = 1; 61 fSpaces[0].offset = offset; 62 fSpaces[0].size = size; 63 } else { 64 fSpaces = NULL; 65 fCount = 0; 66 } 67 68 fCapacity = fCount; 69 70 return B_OK; 71 } 72 73 74 // Unset 75 void 76 BPartitioningInfo::Unset() 77 { 78 delete[] fSpaces; 79 fPartitionID = -1; 80 fSpaces = NULL; 81 fCount = 0; 82 fCapacity = 0; 83 } 84 85 86 // ExcludeOccupiedSpace 87 status_t 88 BPartitioningInfo::ExcludeOccupiedSpace(off_t offset, off_t size) 89 { 90 if (size <= 0) 91 return B_OK; 92 93 TRACE(("%p - BPartitioningInfo::ExcludeOccupiedSpace(offset = %lld, " 94 "size = %lld)\n", this, offset, size)); 95 96 int32 leftIndex = -1; 97 int32 rightIndex = -1; 98 for (int32 i = 0; i < fCount; i++) { 99 if (leftIndex == -1 100 && offset < fSpaces[i].offset + fSpaces[i].size) { 101 leftIndex = i; 102 } 103 104 if (fSpaces[i].offset < offset + size) 105 rightIndex = i; 106 } 107 108 TRACE((" leftIndex = %ld, rightIndex = %ld\n", leftIndex, rightIndex)); 109 110 // If there's no intersection with any free space, we're done. 111 if (leftIndex == -1 || rightIndex == -1 || leftIndex > rightIndex) 112 return B_OK; 113 114 partitionable_space_data& leftSpace = fSpaces[leftIndex]; 115 partitionable_space_data& rightSpace = fSpaces[rightIndex]; 116 117 off_t rightSpaceEnd = rightSpace.offset + rightSpace.size; 118 119 // special case: split a single space in two 120 if (leftIndex == rightIndex && leftSpace.offset < offset 121 && rightSpaceEnd > offset + size) { 122 123 TRACE((" splitting space at %ld\n", leftIndex)); 124 125 // add a space after this one 126 status_t error = _InsertSpaces(leftIndex + 1, 1); 127 if (error != B_OK) 128 return error; 129 130 // IMPORTANT: after calling _InsertSpace(), one can not 131 // use the partitionable_space_data references "leftSpace" 132 // and "rightSpace" anymore (declared above)! 133 134 partitionable_space_data& space = fSpaces[leftIndex]; 135 partitionable_space_data& newSpace = fSpaces[leftIndex + 1]; 136 137 space.size = offset - space.offset; 138 139 newSpace.offset = offset + size; 140 newSpace.size = rightSpaceEnd - newSpace.offset; 141 142 #ifdef TRACING 143 PrintToStream(); 144 #endif 145 return B_OK; 146 } 147 148 // check whether the first affected space is eaten completely 149 int32 deleteFirst = leftIndex; 150 if (leftSpace.offset < offset) { 151 leftSpace.size = offset - leftSpace.offset; 152 153 TRACE((" left space remains, new size is %lld\n", leftSpace.size)); 154 155 deleteFirst++; 156 } 157 158 // check whether the last affected space is eaten completely 159 int32 deleteLast = rightIndex; 160 if (rightSpaceEnd > offset + size) { 161 rightSpace.offset = offset + size; 162 rightSpace.size = rightSpaceEnd - rightSpace.offset; 163 164 TRACE((" right space remains, new offset = %lld, size = %lld\n", 165 rightSpace.offset, rightSpace.size)); 166 167 deleteLast--; 168 } 169 170 // remove all spaces that are completely eaten 171 if (deleteFirst <= deleteLast) 172 _RemoveSpaces(deleteFirst, deleteLast - deleteFirst + 1); 173 174 #ifdef TRACING 175 PrintToStream(); 176 #endif 177 return B_OK; 178 } 179 180 181 // PartitionID 182 partition_id 183 BPartitioningInfo::PartitionID() const 184 { 185 return fPartitionID; 186 } 187 188 189 // GetPartitionableSpaceAt 190 status_t 191 BPartitioningInfo::GetPartitionableSpaceAt(int32 index, off_t *offset, 192 off_t *size) const 193 { 194 if (!fSpaces) 195 return B_NO_INIT; 196 if (!offset || !size) 197 return B_BAD_VALUE; 198 if (index < 0 || index >= fCount) 199 return B_BAD_INDEX; 200 *offset = fSpaces[index].offset; 201 *size = fSpaces[index].size; 202 return B_OK; 203 } 204 205 206 // CountPartitionableSpaces 207 int32 208 BPartitioningInfo::CountPartitionableSpaces() const 209 { 210 return fCount; 211 } 212 213 214 // PrintToStream 215 void 216 BPartitioningInfo::PrintToStream() const 217 { 218 if (!fSpaces) { 219 printf("BPartitioningInfo is not initialized\n"); 220 return; 221 } 222 printf("BPartitioningInfo has %ld spaces:\n", fCount); 223 for (int32 i = 0; i < fCount; i++) { 224 printf(" space at %ld: offset = %lld, size = %lld\n", 225 i, fSpaces[i].offset, fSpaces[i].size); 226 } 227 } 228 229 230 // #pragma mark - 231 232 233 // _InsertSpaces 234 status_t 235 BPartitioningInfo::_InsertSpaces(int32 index, int32 count) 236 { 237 if (index <= 0 || index > fCount || count <= 0) 238 return B_BAD_VALUE; 239 240 // If the capacity is sufficient, we just need to copy the spaces to create 241 // a gap. 242 if (fCount + count <= fCapacity) { 243 memmove(fSpaces + index + count, fSpaces + index, 244 (fCount - index) * sizeof(partitionable_space_data)); 245 fCount += count; 246 return B_OK; 247 } 248 249 // alloc new array 250 int32 capacity = (fCount + count) * 2; 251 // add a bit room for further resizing 252 253 partitionable_space_data* spaces 254 = new(nothrow) partitionable_space_data[capacity]; 255 if (!spaces) 256 return B_NO_MEMORY; 257 258 // copy items 259 memcpy(spaces, fSpaces, index * sizeof(partitionable_space_data)); 260 memcpy(spaces + index + count, fSpaces + index, 261 (fCount - index) * sizeof(partitionable_space_data)); 262 263 delete[] fSpaces; 264 fSpaces = spaces; 265 fCapacity = capacity; 266 fCount += count; 267 268 return B_OK; 269 } 270 271 272 // _RemoveSpaces 273 void 274 BPartitioningInfo::_RemoveSpaces(int32 index, int32 count) 275 { 276 if (index < 0 || count <= 0 || index + count > fCount) 277 return; 278 279 if (count < fCount) { 280 int32 endIndex = index + count; 281 memmove(fSpaces + index, fSpaces + endIndex, 282 (fCount - endIndex) * sizeof(partitionable_space_data)); 283 } 284 285 fCount -= count; 286 } 287