1 /* 2 * Copyright 2002-2008 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Erik Jaesler <ejakowatz@users.sourceforge.net> 7 * Ithamar R. Adema <ithamar@unet.nl> 8 * Stephan Aßmus <superstippi@gmx.de> 9 */ 10 #include "MainWindow.h" 11 #include "DiskView.h" 12 #include "InitParamsPanel.h" 13 #include "PartitionList.h" 14 #include "Support.h" 15 16 #include <Alert.h> 17 #include <Application.h> 18 19 #include <DiskDeviceVisitor.h> 20 #include <DiskSystem.h> 21 #include <DiskDevice.h> 22 #include <Partition.h> 23 #include <PartitioningInfo.h> 24 #include <Path.h> 25 26 #include <ColumnListView.h> 27 #include <ColumnTypes.h> 28 #include <MenuItem.h> 29 #include <MenuBar.h> 30 #include <Menu.h> 31 #include <Screen.h> 32 #include <Volume.h> 33 #include <VolumeRoster.h> 34 35 36 class ListPopulatorVisitor : public BDiskDeviceVisitor { 37 public: 38 ListPopulatorVisitor(PartitionListView* list, int32& diskCount, 39 SpaceIDMap& spaceIDMap) 40 : fPartitionList(list) 41 , fDiskCount(diskCount) 42 , fSpaceIDMap(spaceIDMap) 43 { 44 fDiskCount = 0; 45 fSpaceIDMap.Clear(); 46 // start with an empty list 47 int32 rows = fPartitionList->CountRows(); 48 for (int32 i = rows - 1; i >= 0; i--) { 49 BRow* row = fPartitionList->RowAt(i); 50 fPartitionList->RemoveRow(row); 51 delete row; 52 } 53 } 54 55 virtual bool Visit(BDiskDevice* device) 56 { 57 fDiskCount++; 58 // if we don't prepare the device for modifications, 59 // we cannot get information about available empty 60 // regions on the device or child partitions 61 device->PrepareModifications(); 62 _AddPartition(device); 63 return false; // Don't stop yet! 64 } 65 66 virtual bool Visit(BPartition* partition, int32 level) 67 { 68 _AddPartition(partition); 69 return false; // Don't stop yet! 70 } 71 72 private: 73 void _AddPartition(BPartition* partition) const 74 { 75 // add the partition itself 76 fPartitionList->AddPartition(partition); 77 78 // add any available space on it 79 BPartitioningInfo info; 80 status_t ret = partition->GetPartitioningInfo(&info); 81 if (ret >= B_OK) { 82 partition_id parentID = partition->ID(); 83 off_t offset; 84 off_t size; 85 for (int32 i = 0; 86 info.GetPartitionableSpaceAt(i, &offset, &size) >= B_OK; 87 i++) { 88 // TODO: remove again once Disk Device API is fixed 89 if (!is_valid_partitionable_space(size)) 90 continue; 91 // 92 partition_id id = fSpaceIDMap.SpaceIDFor(parentID, offset); 93 fPartitionList->AddSpace(parentID, id, offset, size); 94 } 95 } 96 } 97 98 PartitionListView* fPartitionList; 99 int32& fDiskCount; 100 SpaceIDMap& fSpaceIDMap; 101 }; 102 103 104 class MountAllVisitor : public BDiskDeviceVisitor { 105 public: 106 MountAllVisitor() 107 { 108 } 109 110 virtual bool Visit(BDiskDevice* device) 111 { 112 return false; // Don't stop yet! 113 } 114 115 virtual bool Visit(BPartition* partition, int32 level) 116 { 117 partition->Mount(); 118 return false; // Don't stop yet! 119 } 120 121 private: 122 PartitionListView* fPartitionList; 123 }; 124 125 126 enum { 127 MSG_MOUNT_ALL = 'mnta', 128 MSG_MOUNT = 'mnts', 129 MSG_UNMOUNT = 'unmt', 130 MSG_FORMAT = 'frmt', 131 MSG_CREATE = 'crtp', 132 MSG_INITIALIZE = 'init', 133 MSG_DELETE = 'delt', 134 MSG_EJECT = 'ejct', 135 MSG_SURFACE_TEST = 'sfct', 136 MSG_RESCAN = 'rscn', 137 138 MSG_PARTITION_ROW_SELECTED = 'prsl', 139 }; 140 141 142 // #pragma mark - 143 144 145 MainWindow::MainWindow(BRect frame) 146 : BWindow(frame, "DriveSetup", B_DOCUMENT_WINDOW, 147 B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE) 148 , fCurrentDisk(NULL) 149 , fCurrentPartitionID(-1) 150 , fSpaceIDMap() 151 { 152 BMenuBar* menuBar = new BMenuBar(Bounds(), "root menu"); 153 154 // create all the menu items 155 fFormatMI = new BMenuItem("Format (not implemented)", new BMessage(MSG_FORMAT)); 156 fEjectMI = new BMenuItem("Eject", new BMessage(MSG_EJECT), 'E'); 157 fSurfaceTestMI = new BMenuItem("Surface Test (not implemented)", 158 new BMessage(MSG_SURFACE_TEST)); 159 fRescanMI = new BMenuItem("Rescan", new BMessage(MSG_RESCAN)); 160 161 fDeleteMI = new BMenuItem("Delete (not implemented)", 162 new BMessage(MSG_DELETE)); 163 fDeleteMI->SetEnabled(false); 164 165 fMountMI = new BMenuItem("Mount", new BMessage(MSG_MOUNT), 'M'); 166 fUnmountMI = new BMenuItem("Unmount", new BMessage(MSG_UNMOUNT), 'U'); 167 fMountAllMI = new BMenuItem("Mount All", 168 new BMessage(MSG_MOUNT_ALL), 'M', B_SHIFT_KEY); 169 170 // Disk menu 171 fDiskMenu = new BMenu("Disk"); 172 fDiskMenu->AddItem(fFormatMI); 173 fDiskMenu->AddItem(fEjectMI); 174 fDiskMenu->AddItem(fSurfaceTestMI); 175 176 fDiskMenu->AddSeparatorItem(); 177 178 fDiskMenu->AddItem(fRescanMI); 179 menuBar->AddItem(fDiskMenu); 180 181 // Parition menu 182 fPartitionMenu = new BMenu("Partition"); 183 fCreateMenu = new BMenu("Create (not implemented)"); 184 fPartitionMenu->AddItem(fCreateMenu); 185 186 fInitMenu = new BMenu("Initialize"); 187 fPartitionMenu->AddItem(fInitMenu); 188 189 fPartitionMenu->AddItem(fDeleteMI); 190 191 fPartitionMenu->AddSeparatorItem(); 192 193 fPartitionMenu->AddItem(fMountMI); 194 fPartitionMenu->AddItem(fUnmountMI); 195 196 fPartitionMenu->AddSeparatorItem(); 197 198 fPartitionMenu->AddItem(fMountAllMI); 199 menuBar->AddItem(fPartitionMenu); 200 201 AddChild(menuBar); 202 203 204 // add DiskView 205 BRect r(Bounds()); 206 r.top = menuBar->Frame().bottom + 1; 207 r.bottom = floorf(r.top + r.Height() * 0.33); 208 fDiskView = new DiskView(r, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, 209 fSpaceIDMap); 210 AddChild(fDiskView); 211 212 // add PartitionListView 213 r.top = r.bottom + 2; 214 r.bottom = Bounds().bottom; 215 r.InsetBy(-1, -1); 216 fListView = new PartitionListView(r, B_FOLLOW_ALL); 217 AddChild(fListView); 218 219 // configure PartitionListView 220 fListView->SetSelectionMessage(new BMessage(MSG_PARTITION_ROW_SELECTED)); 221 fListView->SetTarget(this); 222 223 // populate the Initialiaze menu with the available file systems 224 _ScanFileSystems(); 225 226 // visit all disks in the system and show their contents 227 _ScanDrives(); 228 } 229 230 231 MainWindow::~MainWindow() 232 { 233 delete fCurrentDisk; 234 } 235 236 237 void 238 MainWindow::MessageReceived(BMessage* message) 239 { 240 switch (message->what) { 241 case MSG_MOUNT_ALL: 242 _MountAll(); 243 break; 244 case MSG_MOUNT: 245 _Mount(fCurrentDisk, fCurrentPartitionID); 246 break; 247 case MSG_UNMOUNT: 248 _Unmount(fCurrentDisk, fCurrentPartitionID); 249 break; 250 251 case MSG_FORMAT: 252 printf("MSG_FORMAT\n"); 253 break; 254 255 case MSG_CREATE: 256 printf("MSG_CREATE\n"); 257 break; 258 259 case MSG_INITIALIZE: { 260 BString diskSystemName; 261 if (message->FindString("format", &diskSystemName) != B_OK) 262 break; 263 _Initialize(fCurrentDisk, fCurrentPartitionID, diskSystemName); 264 break; 265 } 266 267 case MSG_DELETE: 268 printf("MSG_DELETE\n"); 269 break; 270 271 case MSG_EJECT: 272 // TODO: completely untested, especially interesting 273 // if partition list behaves when partitions disappear 274 if (fCurrentDisk) { 275 // TODO: only if no partitions are mounted anymore? 276 fCurrentDisk->Eject(true); 277 _ScanDrives(); 278 } 279 break; 280 case MSG_SURFACE_TEST: 281 printf("MSG_SURFACE_TEST\n"); 282 break; 283 case MSG_RESCAN: 284 _ScanDrives(); 285 break; 286 287 case MSG_PARTITION_ROW_SELECTED: 288 // selection of partitions via list view 289 _AdaptToSelectedPartition(); 290 break; 291 case MSG_SELECTED_PARTITION_ID: { 292 // selection of partitions via disk view 293 partition_id id; 294 if (message->FindInt32("partition_id", &id) == B_OK) { 295 if (BRow* row = fListView->FindRow(id)) { 296 fListView->DeselectAll(); 297 fListView->AddToSelection(row); 298 _AdaptToSelectedPartition(); 299 } 300 } 301 break; 302 } 303 304 default: 305 BWindow::MessageReceived(message); 306 break; 307 } 308 } 309 310 311 bool 312 MainWindow::QuitRequested() 313 { 314 // TODO: ask about any unsaved changes 315 be_app->PostMessage(B_QUIT_REQUESTED); 316 Hide(); 317 return false; 318 } 319 320 321 // #pragma mark - 322 323 324 status_t 325 MainWindow::StoreSettings(BMessage* archive) const 326 { 327 if (archive->ReplaceRect("window frame", Frame()) < B_OK) 328 archive->AddRect("window frame", Frame()); 329 330 BMessage columnSettings; 331 fListView->SaveState(&columnSettings); 332 if (archive->ReplaceMessage("column settings", &columnSettings) < B_OK) 333 archive->AddMessage("column settings", &columnSettings); 334 335 return B_OK; 336 } 337 338 339 status_t 340 MainWindow::RestoreSettings(BMessage* archive) 341 { 342 BRect frame; 343 if (archive->FindRect("window frame", &frame) == B_OK) { 344 BScreen screen(this); 345 if (frame.Intersects(screen.Frame())) { 346 MoveTo(frame.LeftTop()); 347 ResizeTo(frame.Width(), frame.Height()); 348 } 349 } 350 351 BMessage columnSettings; 352 if (archive->FindMessage("column settings", &columnSettings) == B_OK) 353 fListView->LoadState(&columnSettings); 354 355 return B_OK; 356 } 357 358 359 // #pragma mark - 360 361 362 void 363 MainWindow::_ScanDrives() 364 { 365 fSpaceIDMap.Clear(); 366 int32 diskCount = 0; 367 ListPopulatorVisitor driveVisitor(fListView, diskCount, fSpaceIDMap); 368 fDDRoster.VisitEachPartition(&driveVisitor); 369 fDiskView->SetDiskCount(diskCount); 370 371 // restore selection 372 PartitionListRow* previousSelection 373 = fListView->FindRow(fCurrentPartitionID); 374 if (previousSelection) { 375 fListView->AddToSelection(previousSelection); 376 _EnabledDisableMenuItems(fCurrentDisk, fCurrentPartitionID, 377 previousSelection->ParentID()); 378 } else { 379 _EnabledDisableMenuItems(NULL, -1, -1); 380 } 381 } 382 383 384 void 385 MainWindow::_ScanFileSystems() 386 { 387 while (BMenuItem* item = fInitMenu->RemoveItem(0L)) 388 delete item; 389 390 BDiskSystem diskSystem; 391 fDDRoster.RewindDiskSystems(); 392 while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { 393 if (diskSystem.IsFileSystem() && diskSystem.SupportsInitializing()) { 394 BMessage* message = new BMessage(MSG_INITIALIZE); 395 message->AddString("format", diskSystem.PrettyName()); 396 BString label = diskSystem.PrettyName(); 397 label << B_UTF8_ELLIPSIS; 398 fInitMenu->AddItem(new BMenuItem(label.String(), message)); 399 } 400 } 401 } 402 403 404 // #pragma mark - 405 406 407 void 408 MainWindow::_AdaptToSelectedPartition() 409 { 410 partition_id diskID = -1; 411 partition_id partitionID = -1; 412 partition_id parentID = -1; 413 414 BRow* _selectedRow = fListView->CurrentSelection(); 415 if (_selectedRow) { 416 // go up to top level row 417 BRow* _topLevelRow = _selectedRow; 418 BRow* parent = NULL; 419 while (fListView->FindParent(_topLevelRow, &parent, NULL)) 420 _topLevelRow = parent; 421 422 PartitionListRow* topLevelRow 423 = dynamic_cast<PartitionListRow*>(_topLevelRow); 424 PartitionListRow* selectedRow 425 = dynamic_cast<PartitionListRow*>(_selectedRow); 426 427 if (topLevelRow) 428 diskID = topLevelRow->ID(); 429 if (selectedRow) { 430 partitionID = selectedRow->ID(); 431 parentID = selectedRow->ParentID(); 432 } 433 } 434 435 _SetToDiskAndPartition(diskID, partitionID, parentID); 436 } 437 438 439 void 440 MainWindow::_SetToDiskAndPartition(partition_id disk, partition_id partition, 441 partition_id parent) 442 { 443 BDiskDevice* oldDisk = NULL; 444 if (!fCurrentDisk || fCurrentDisk->ID() != disk) { 445 oldDisk = fCurrentDisk; 446 fCurrentDisk = NULL; 447 if (disk >= 0) { 448 BDiskDevice* newDisk = new BDiskDevice(); 449 status_t ret = newDisk->SetTo(disk); 450 if (ret < B_OK) { 451 printf("error switching disks: %s\n", strerror(ret)); 452 delete newDisk; 453 } else 454 fCurrentDisk = newDisk; 455 } 456 } 457 458 fCurrentPartitionID = partition; 459 460 fDiskView->SetDisk(fCurrentDisk, fCurrentPartitionID); 461 _EnabledDisableMenuItems(fCurrentDisk, fCurrentPartitionID, parent); 462 463 delete oldDisk; 464 } 465 466 467 void 468 MainWindow::_EnabledDisableMenuItems(BDiskDevice* disk, 469 partition_id selectedPartition, partition_id parentID) 470 { 471 // clean out Create menu 472 while (BMenuItem* item = fCreateMenu->RemoveItem(0L)) 473 delete item; 474 475 if (!disk) { 476 fFormatMI->SetEnabled(false); 477 fEjectMI->SetEnabled(false); 478 fSurfaceTestMI->SetEnabled(false); 479 480 fPartitionMenu->SetEnabled(false); 481 } else { 482 // fFormatMI->SetEnabled(true); 483 fFormatMI->SetEnabled(false); 484 fEjectMI->SetEnabled(disk->IsRemovableMedia()); 485 // fSurfaceTestMI->SetEnabled(true); 486 fSurfaceTestMI->SetEnabled(false); 487 488 // Create menu and items 489 fPartitionMenu->SetEnabled(true); 490 491 BPartition* parentPartition = NULL; 492 if (selectedPartition <= -2) 493 parentPartition = disk->FindDescendant(parentID); 494 495 if (parentPartition) { 496 disk->PrepareModifications(); 497 fCreateMenu->SetEnabled(true); 498 BString supportedChildType; 499 int32 cookie = 0; 500 status_t ret; 501 while ((ret = parentPartition->GetNextSupportedChildType(&cookie, 502 &supportedChildType)) == B_OK) { 503 BMessage* message = new BMessage(MSG_CREATE); 504 message->AddInt32("parent id", parentID); 505 message->AddInt32("space id", selectedPartition); 506 message->AddString("type", supportedChildType); 507 BMenuItem* item = new BMenuItem(supportedChildType.String(), 508 message); 509 fCreateMenu->AddItem(item); 510 } 511 if (fCreateMenu->CountItems() == 0) 512 fprintf(stderr, "Failed to get supported child types: %s\n", 513 strerror(ret)); 514 disk->CancelModifications(); 515 } else { 516 fCreateMenu->SetEnabled(false); 517 } 518 519 // Mount items 520 BPartition* partition = disk->FindDescendant(selectedPartition); 521 if (partition) { 522 fInitMenu->SetEnabled(!partition->IsMounted()); 523 // fDeleteMI->SetEnabled(!partition->IsMounted()); 524 fDeleteMI->SetEnabled(false); 525 fMountMI->SetEnabled(!partition->IsMounted()); 526 527 bool unMountable = false; 528 if (partition->IsMounted()) { 529 // see if this partition is the boot volume 530 BVolume volume; 531 BVolume bootVolume; 532 if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK 533 && partition->GetVolume(&volume) == B_OK) { 534 unMountable = volume != bootVolume; 535 } else 536 unMountable = true; 537 } 538 fUnmountMI->SetEnabled(unMountable); 539 } else { 540 fInitMenu->SetEnabled(false); 541 fDeleteMI->SetEnabled(false); 542 fMountMI->SetEnabled(false); 543 fUnmountMI->SetEnabled(false); 544 } 545 fMountAllMI->SetEnabled(true); 546 } 547 } 548 549 550 void 551 MainWindow::_DisplayPartitionError(BString _message, 552 const BPartition* partition, status_t error) const 553 { 554 char message[1024]; 555 556 if (partition && _message.FindFirst("%s") >= 0) { 557 BString name; 558 name << " \"" << partition->ContentName() << "\""; 559 sprintf(message, _message.String(), name.String()); 560 } else { 561 _message.ReplaceAll("%s", ""); 562 sprintf(message, _message.String()); 563 } 564 565 if (error < B_OK) { 566 BString helper = message; 567 sprintf(message, "%s\n\nError: %s", helper.String(), strerror(error)); 568 } 569 570 BAlert* alert = new BAlert("error", message, "Ok", NULL, NULL, 571 B_WIDTH_FROM_WIDEST, error < B_OK ? B_STOP_ALERT : B_INFO_ALERT); 572 alert->Go(NULL); 573 } 574 575 576 // #pragma mark - 577 578 579 void 580 MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition) 581 { 582 if (!disk || selectedPartition < 0) { 583 _DisplayPartitionError("You need to select a partition " 584 "entry from the list."); 585 return; 586 } 587 588 BPartition* partition = disk->FindDescendant(selectedPartition); 589 if (!partition) { 590 _DisplayPartitionError("Unable to find the selected partition by id."); 591 return; 592 } 593 594 if (!partition->IsMounted()) { 595 status_t ret = partition->Mount(); 596 if (ret < B_OK) { 597 _DisplayPartitionError("Could not mount partition %s.", 598 partition, ret); 599 } else { 600 // successful mount, adapt to the changes 601 _ScanDrives(); 602 } 603 } else { 604 _DisplayPartitionError("The partition %s is already mounted.", 605 partition); 606 } 607 } 608 609 610 void 611 MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition) 612 { 613 if (!disk || selectedPartition < 0) { 614 _DisplayPartitionError("You need to select a partition " 615 "entry from the list."); 616 return; 617 } 618 619 BPartition* partition = disk->FindDescendant(selectedPartition); 620 if (!partition) { 621 _DisplayPartitionError("Unable to find the selected partition by id."); 622 return; 623 } 624 625 if (partition->IsMounted()) { 626 status_t ret = partition->Unmount(); 627 if (ret < B_OK) { 628 _DisplayPartitionError("Could not unmount partition %s.", 629 partition, ret); 630 } else { 631 // successful unmount, adapt to the changes 632 _ScanDrives(); 633 } 634 } else { 635 _DisplayPartitionError("The partition %s is already unmounted.", 636 partition); 637 } 638 } 639 640 641 void 642 MainWindow::_MountAll() 643 { 644 MountAllVisitor visitor; 645 fDDRoster.VisitEachPartition(&visitor); 646 } 647 648 649 // #pragma mark - 650 651 652 void 653 MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition, 654 const BString& diskSystemName) 655 { 656 if (!disk || selectedPartition < 0) { 657 _DisplayPartitionError("You need to select a partition " 658 "entry from the list."); 659 return; 660 } 661 662 if (disk->IsReadOnly()) { 663 _DisplayPartitionError("The selected disk is read-only."); 664 return; 665 } 666 667 BPartition* partition = disk->FindDescendant(selectedPartition); 668 if (!partition) { 669 _DisplayPartitionError("Unable to find the selected partition by id."); 670 return; 671 } 672 673 if (partition->IsMounted()) { 674 _DisplayPartitionError("The partition %s is currently mounted."); 675 // TODO: option to unmount and continue on success to unmount 676 return; 677 } 678 679 BString message("Are you sure you want to initialize the partition "); 680 message << "\"" << partition->ContentName(); 681 message << "\"? After entering the initialization parameters, "; 682 message << "you can abort this operation right before writing "; 683 message << "changes back to the disk."; 684 BAlert* alert = new BAlert("first notice", message.String(), 685 "Continue", "Cancel", NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 686 int32 choice = alert->Go(); 687 688 if (choice == 1) 689 return; 690 691 BDiskSystem diskSystem; 692 fDDRoster.RewindDiskSystems(); 693 bool found = false; 694 while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { 695 if (diskSystem.IsFileSystem() && diskSystem.SupportsInitializing()) { 696 if (diskSystemName == diskSystem.PrettyName()) { 697 found = true; 698 break; 699 } 700 } 701 } 702 703 if (!found) { 704 BString message("Disk system \""); 705 message << diskSystemName << "\" not found!"; 706 _DisplayPartitionError(message); 707 return; 708 } 709 710 711 // allow BFS only, since our parameter string 712 // construction only handles BFS at the moment 713 if (diskSystemName != "Be File System") { 714 _DisplayPartitionError("Don't know how to construct parameters " 715 "for this file system."); 716 return; 717 } 718 719 status_t ret = disk->PrepareModifications(); 720 if (ret != B_OK) { 721 _DisplayPartitionError("There was an error preparing the " 722 "disk for modifications.", NULL, ret); 723 return; 724 } 725 726 // TODO: use partition initialization editor 727 // (partition->GetInitializationParameterEditor()) 728 729 BString name = "Haiku"; 730 BString parameters; 731 InitParamsPanel* panel = new InitParamsPanel(this); 732 panel->Go(name, parameters); 733 734 bool supportsName = diskSystem.SupportsContentName(); 735 BString validatedName(name); 736 ret = partition->ValidateInitialize(diskSystem.PrettyName(), 737 supportsName ? &validatedName : NULL, parameters.String()); 738 if (ret != B_OK) { 739 _DisplayPartitionError("Validation of the given initialization " 740 "parameters failed.", partition, ret); 741 return; 742 } 743 744 BString previousName = partition->ContentName(); 745 746 ret = partition->Initialize(diskSystem.PrettyName(), 747 supportsName ? name.String() : NULL, parameters.String()); 748 if (ret != B_OK) { 749 _DisplayPartitionError("Initialization of the partition %s " 750 "failed. (Nothing has been written to disk.)", partition, ret); 751 return; 752 } 753 754 // everything looks fine, we are ready to actually write the changes 755 // to disk 756 757 message = "Are you sure you want to write the changes back to " 758 "disk now?\n\n"; 759 message << "All data on the partition \"" << previousName; 760 message << "\" will be irrevertably lost if you do so!"; 761 alert = new BAlert("final notice", message.String(), 762 "Write Changes", "Cancel", NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); 763 choice = alert->Go(); 764 765 if (choice == 1) 766 return; 767 768 // commit 769 ret = disk->CommitModifications(); 770 if (ret == B_OK) { 771 _DisplayPartitionError("The partition %s has been successfully " 772 "initialized.\n", partition); 773 } else { 774 _DisplayPartitionError("Failed to initialize the partition " 775 "%s!\n", partition, ret); 776 } 777 778 _ScanDrives(); 779 } 780 781