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