1 /* 2 * Copyright 2007, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ExtendedPartitionAddOn.h" 8 9 #include <new> 10 #include <stdio.h> 11 12 #include <DiskDeviceTypes.h> 13 #include <MutablePartition.h> 14 #include <PartitioningInfo.h> 15 16 #include <AutoDeleter.h> 17 18 #include "IntelDiskSystem.h" 19 20 21 //#define TRACE_EXTENDED_PARTITION_ADD_ON 22 #undef TRACE 23 #ifdef TRACE_EXTENDED_PARTITION_ADD_ON 24 # define TRACE(x...) printf(x) 25 #else 26 # define TRACE(x...) do {} while (false) 27 #endif 28 29 #define PTS_OFFSET (63 * Partition()->BlockSize()) 30 31 32 using std::nothrow; 33 34 35 static const uint32 kDiskSystemFlags = 36 0 37 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 38 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 39 // | B_DISK_SYSTEM_SUPPORTS_RESIZING 40 // | B_DISK_SYSTEM_SUPPORTS_MOVING 41 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 42 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 43 // | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 44 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 45 46 // | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 47 // | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 48 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 49 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 50 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 51 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 52 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 53 // | B_DISK_SYSTEM_SUPPORTS_NAME 54 ; 55 56 57 // #pragma mark - ExtendedPartitionAddOn 58 59 60 ExtendedPartitionAddOn::ExtendedPartitionAddOn() 61 : 62 BDiskSystemAddOn(kPartitionTypeIntelExtended, kDiskSystemFlags) 63 { 64 } 65 66 67 ExtendedPartitionAddOn::~ExtendedPartitionAddOn() 68 { 69 } 70 71 72 status_t 73 ExtendedPartitionAddOn::CreatePartitionHandle(BMutablePartition* partition, 74 BPartitionHandle** _handle) 75 { 76 ExtendedPartitionHandle* handle 77 = new(nothrow) ExtendedPartitionHandle(partition); 78 if (!handle) 79 return B_NO_MEMORY; 80 81 status_t error = handle->Init(); 82 if (error != B_OK) { 83 delete handle; 84 return error; 85 } 86 87 *_handle = handle; 88 return B_OK; 89 } 90 91 92 bool 93 ExtendedPartitionAddOn::CanInitialize(const BMutablePartition* partition) 94 { 95 // If it's big enough, we can initialize it. 96 return false; 97 } 98 99 100 status_t 101 ExtendedPartitionAddOn::GetInitializationParameterEditor( 102 const BMutablePartition* partition, BPartitionParameterEditor** editor) 103 { 104 // Nothing to edit, really. 105 *editor = NULL; 106 return B_OK; 107 } 108 109 110 status_t 111 ExtendedPartitionAddOn::ValidateInitialize(const BMutablePartition* partition, 112 BString* name, const char* parameters) 113 { 114 if (!CanInitialize(partition) 115 || (parameters != NULL && parameters[0] != '\0')) { 116 return B_BAD_VALUE; 117 } 118 119 // we don't support a content name 120 if (name != NULL) 121 name->Truncate(0); 122 123 return B_OK; 124 } 125 126 127 status_t 128 ExtendedPartitionAddOn::Initialize(BMutablePartition* partition, 129 const char* name, const char* parameters, BPartitionHandle** _handle) 130 { 131 if (!CanInitialize(partition) 132 || (name != NULL && name[0] != '\0') 133 || (parameters != NULL && parameters[0] != '\0')) { 134 return B_BAD_VALUE; 135 } 136 137 // create the handle 138 ExtendedPartitionHandle* handle 139 = new(nothrow) ExtendedPartitionHandle(partition); 140 if (!handle) 141 return B_NO_MEMORY; 142 ObjectDeleter<ExtendedPartitionHandle> handleDeleter(handle); 143 144 // init the partition 145 status_t error = partition->SetContentType(Name()); 146 if (error != B_OK) 147 return error; 148 // TODO: The content type could as well be set by the caller. 149 150 partition->SetContentName(NULL); 151 partition->SetContentParameters(NULL); 152 partition->SetContentSize( 153 sector_align(partition->Size(), partition->BlockSize())); 154 155 *_handle = handleDeleter.Detach(); 156 157 return B_OK; 158 } 159 160 161 // #pragma mark - ExtendedPartitionHandle 162 163 164 ExtendedPartitionHandle::ExtendedPartitionHandle(BMutablePartition* partition) 165 : 166 BPartitionHandle(partition) 167 { 168 } 169 170 171 ExtendedPartitionHandle::~ExtendedPartitionHandle() 172 { 173 } 174 175 176 status_t 177 ExtendedPartitionHandle::Init() 178 { 179 // initialize the extended partition from the mutable partition 180 181 BMutablePartition* partition = Partition(); 182 183 // our parent has already set the child cookie to the primary partition. 184 fPrimaryPartition = (PrimaryPartition*)partition->ChildCookie(); 185 if (!fPrimaryPartition) 186 return B_BAD_VALUE; 187 188 if (!fPrimaryPartition->IsExtended()) 189 return B_BAD_VALUE; 190 191 // init the child partitions 192 int32 count = partition->CountChildren(); 193 for (int32 i = 0; i < count; i++) { 194 BMutablePartition* child = partition->ChildAt(i); 195 196 PartitionType type; 197 if (!type.SetType(child->Type())) 198 return B_BAD_VALUE; 199 200 void* handle = parse_driver_settings_string(child->Parameters()); 201 if (handle == NULL) 202 return B_ERROR; 203 204 bool active = get_driver_boolean_parameter( 205 handle, "active", false, true); 206 207 off_t ptsOffset = 0; 208 const char* buffer = get_driver_parameter(handle, 209 "partition_table_offset", NULL, NULL); 210 if (buffer != NULL) 211 ptsOffset = strtoull(buffer, NULL, 10); 212 else { 213 delete_driver_settings(handle); 214 return B_BAD_VALUE; 215 } 216 delete_driver_settings(handle); 217 218 LogicalPartition* logical = new(nothrow) LogicalPartition; 219 if (!logical) 220 return B_NO_MEMORY; 221 222 logical->SetTo(child->Offset(), child->Size(), type.Type(), active, 223 ptsOffset, fPrimaryPartition); 224 225 child->SetChildCookie(logical); 226 } 227 228 return B_OK; 229 } 230 231 232 uint32 233 ExtendedPartitionHandle::SupportedOperations(uint32 mask) 234 { 235 uint32 flags = 0; 236 237 // creating child 238 if ((mask & B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD) != 0) { 239 BPartitioningInfo info; 240 if (GetPartitioningInfo(&info) == B_OK 241 && info.CountPartitionableSpaces() > 1) { 242 flags |= B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD; 243 } 244 } 245 246 return flags; 247 } 248 249 250 uint32 251 ExtendedPartitionHandle::SupportedChildOperations( 252 const BMutablePartition* child, uint32 mask) 253 { 254 return B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD; 255 } 256 257 258 status_t 259 ExtendedPartitionHandle::GetNextSupportedType(const BMutablePartition* child, 260 int32* cookie, BString* type) 261 { 262 int32 index = *cookie; 263 const partition_type* nextType; 264 PartitionMap partitionMap; 265 while (true) { 266 nextType = partitionMap.GetNextSupportedPartitionType(index); 267 if (nextType == NULL) 268 return B_ENTRY_NOT_FOUND; 269 index++; 270 if (nextType->used 271 && strcmp(nextType->name, kPartitionTypeIntelExtended) != 0) 272 break; 273 } 274 275 if (!nextType) 276 return B_ENTRY_NOT_FOUND; 277 278 type->SetTo(nextType->name); 279 *cookie = index; 280 281 return B_OK; 282 } 283 284 285 status_t 286 ExtendedPartitionHandle::GetPartitioningInfo(BPartitioningInfo* info) 287 { 288 // init to the full size (minus the first PTS_OFFSET) 289 BMutablePartition* partition = Partition(); 290 off_t offset = partition->Offset() + PTS_OFFSET; 291 off_t size = partition->Size() - PTS_OFFSET; 292 status_t error = info->SetTo(offset, size); 293 if (error != B_OK) 294 return error; 295 296 // exclude the space of the existing logical partitions 297 int32 count = partition->CountChildren(); 298 for (int32 i = 0; i < count; i++) { 299 BMutablePartition* child = partition->ChildAt(i); 300 error = info->ExcludeOccupiedSpace(child->Offset(), 301 child->Size() + PTS_OFFSET + Partition()->BlockSize()); 302 if (error != B_OK) 303 return error; 304 305 LogicalPartition* logical = (LogicalPartition*)child->ChildCookie(); 306 if (logical == NULL) 307 return B_BAD_VALUE; 308 error = info->ExcludeOccupiedSpace( 309 logical->PartitionTableOffset(), 310 PTS_OFFSET + Partition()->BlockSize()); 311 if (error != B_OK) 312 return error; 313 } 314 315 return B_OK; 316 } 317 318 319 status_t 320 ExtendedPartitionHandle::GetChildCreationParameterEditor(const char* type, 321 BPartitionParameterEditor** editor) 322 { 323 *editor = NULL; 324 return B_OK; 325 } 326 327 328 status_t 329 ExtendedPartitionHandle::ValidateCreateChild(off_t* _offset, off_t* _size, 330 const char* typeString, BString* name, const char* parameters) 331 { 332 // check type 333 if (!typeString) 334 return B_BAD_VALUE; 335 336 // check name 337 if (name) 338 name->Truncate(0); 339 340 // check the free space situation 341 BPartitioningInfo info; 342 status_t error = GetPartitioningInfo(&info); 343 if (error != B_OK) 344 return error; 345 346 // any space in the partition at all? 347 int32 spacesCount = info.CountPartitionableSpaces(); 348 if (spacesCount == 0) 349 return B_BAD_VALUE; 350 351 // check offset and size 352 off_t offset = sector_align(*_offset, Partition()->BlockSize()); 353 off_t size = sector_align(*_size, Partition()->BlockSize()); 354 // TODO: Rather round size up? 355 off_t end = offset + size; 356 357 // get the first partitionable space the requested interval intersects with 358 int32 spaceIndex = -1; 359 int32 closestSpaceIndex = -1; 360 off_t closestSpaceDistance = 0; 361 for (int32 i = 0; i < spacesCount; i++) { 362 off_t spaceOffset, spaceSize; 363 info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize); 364 off_t spaceEnd = spaceOffset + spaceSize; 365 366 if ((spaceOffset >= offset && spaceOffset < end) 367 || (offset >= spaceOffset && offset < spaceEnd)) { 368 spaceIndex = i; 369 break; 370 } 371 372 off_t distance; 373 if (offset < spaceOffset) 374 distance = spaceOffset - end; 375 else 376 distance = spaceEnd - offset; 377 378 if (closestSpaceIndex == -1 || distance < closestSpaceDistance) { 379 closestSpaceIndex = i; 380 closestSpaceDistance = distance; 381 } 382 } 383 384 // get the space we found 385 off_t spaceOffset, spaceSize; 386 info.GetPartitionableSpaceAt( 387 spaceIndex >= 0 ? spaceIndex : closestSpaceIndex, &spaceOffset, 388 &spaceSize); 389 off_t spaceEnd = spaceOffset + spaceSize; 390 391 // If the requested intervald doesn't intersect with any space yet, move 392 // it, so that it does. 393 if (spaceIndex < 0) { 394 spaceIndex = closestSpaceIndex; 395 if (offset < spaceOffset) { 396 offset = spaceOffset; 397 end = offset + size; 398 } else { 399 end = spaceEnd; 400 offset = end - size; 401 } 402 } 403 404 // move/shrink the interval, so that it fully lies within the space 405 if (offset < spaceOffset) { 406 offset = spaceOffset; 407 end = offset + size; 408 if (end > spaceEnd) { 409 end = spaceEnd; 410 size = end - offset; 411 } 412 } else if (end > spaceEnd) { 413 end = spaceEnd; 414 offset = end - size; 415 if (offset < spaceOffset) { 416 offset = spaceOffset; 417 size = end - offset; 418 } 419 } 420 421 *_offset = offset; 422 *_size = size; 423 424 return B_OK; 425 } 426 427 428 status_t 429 ExtendedPartitionHandle::CreateChild(off_t offset, off_t size, 430 const char* typeString, const char* name, const char* _parameters, 431 BMutablePartition** _child) 432 { 433 // check type 434 PartitionType type; 435 if (!type.SetType(typeString) || type.IsEmpty()) 436 return B_BAD_VALUE; 437 438 // check name 439 if (name != NULL && name[0] != '\0') 440 return B_BAD_VALUE; 441 442 // offset properly aligned? 443 if (offset != sector_align(offset, Partition()->BlockSize()) 444 || size != sector_align(size, Partition()->BlockSize())) 445 return B_BAD_VALUE; 446 447 // check the free space situation 448 BPartitioningInfo info; 449 status_t error = GetPartitioningInfo(&info); 450 if (error != B_OK) 451 return error; 452 453 bool foundSpace = false; 454 off_t end = offset + size; 455 int32 spacesCount = info.CountPartitionableSpaces(); 456 for (int32 i = 0; i < spacesCount; i++) { 457 off_t spaceOffset, spaceSize; 458 info.GetPartitionableSpaceAt(i, &spaceOffset, &spaceSize); 459 off_t spaceEnd = spaceOffset + spaceSize; 460 461 if (offset >= spaceOffset && end <= spaceEnd) { 462 foundSpace = true; 463 break; 464 } 465 } 466 467 if (!foundSpace) 468 return B_BAD_VALUE; 469 470 BString parameters(_parameters); 471 parameters << "partition_table_offset " << offset - PTS_OFFSET << " ;\n"; 472 // everything looks good, create the child 473 BMutablePartition* child; 474 error = Partition()->CreateChild(-1, typeString, 475 NULL, parameters.String(), &child); 476 if (error != B_OK) 477 return error; 478 479 // init the child 480 child->SetOffset(offset); 481 child->SetSize(size); 482 child->SetBlockSize(Partition()->BlockSize()); 483 //child->SetFlags(0); 484 child->SetChildCookie(Partition()); 485 486 *_child = child; 487 return B_OK; 488 } 489 490 491 status_t 492 ExtendedPartitionHandle::DeleteChild(BMutablePartition* child) 493 { 494 BMutablePartition* parent = child->Parent(); 495 status_t error = parent->DeleteChild(child); 496 497 return error; 498 } 499