// _SetTo status_t BPartition::_SetTo(BDiskDevice* device, BPartition* parent, user_partition_data* data) { _Unset(); if (!device || !data) return B_BAD_VALUE; fPartitionData = data; fDevice = device; fParent = parent; fPartitionData->user_data = this; // create and init children status_t error = B_OK; for (int32 i = 0; error == B_OK && i < fPartitionData->child_count; i++) { BPartition* child = new(nothrow) BPartition; if (child) { error = child->_SetTo(fDevice, this, fPartitionData->children[i]); if (error != B_OK) delete child; } else error = B_NO_MEMORY; } // cleanup on error if (error != B_OK) _Unset(); return error; }
void MainWindow::_Mount(BDiskDevice* disk, partition_id selectedPartition) { if (!disk || selectedPartition < 0) { _DisplayPartitionError(B_TRANSLATE("You need to select a partition " "entry from the list.")); return; } BPartition* partition = disk->FindDescendant(selectedPartition); if (!partition) { _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " "partition by ID.")); return; } if (!partition->IsMounted()) { status_t ret = partition->Mount(); if (ret < B_OK) { _DisplayPartitionError( B_TRANSLATE("Could not mount partition %s."), partition, ret); } else { // successful mount, adapt to the changes _ScanDrives(); } } else { _DisplayPartitionError( B_TRANSLATE("The partition %s is already mounted."), partition); } }
// _CreateDelegates status_t BPartition::_CreateDelegates() { if (fDelegate || !fPartitionData) return B_NO_INIT; // create and init delegate fDelegate = new(nothrow) Delegate(this); if (!fDelegate) return B_NO_MEMORY; status_t error = fDelegate->InitHierarchy(fPartitionData, fParent ? fParent->fDelegate : NULL); if (error != B_OK) return error; // create child delegates int32 count = _CountChildren(); for (int32 i = 0; i < count; i++) { BPartition* child = _ChildAt(i); error = child->_CreateDelegates(); if (error != B_OK) return error; } return B_OK; }
void AutoMounter::_MountVolume(const BMessage* message) { int32 id; if (message->FindInt32("id", &id) != B_OK) return; BDiskDeviceRoster roster; BPartition *partition; BDiskDevice device; if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) return; uint32 mountFlags; if (!_SuggestMountFlags(partition, &mountFlags)) return; status_t status = partition->Mount(NULL, mountFlags); if (status < B_OK) { char text[512]; snprintf(text, sizeof(text), B_TRANSLATE("Error mounting volume:\n\n%s"), strerror(status)); BAlert* alert = new BAlert(B_TRANSLATE("Mount error"), text, B_TRANSLATE("OK")); alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); alert->Go(NULL); } }
// CanMove bool BPartition::CanMove(BObjectList<BPartition>* unmovableDescendants, BObjectList<BPartition>* movableOnlyIfUnmounted) const { BPartition* parent = Parent(); if (!parent || !fDelegate) return false; if (!parent->_SupportsChildOperation(this, B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD)) { return false; } bool whileMounted; bool movable = _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_MOVING, B_DISK_SYSTEM_SUPPORTS_MOVING_WHILE_MOUNTED, &whileMounted); if (!movable) return false; if (!whileMounted) movableOnlyIfUnmounted->AddItem(const_cast<BPartition*>(this)); // collect descendent partitions // TODO: ... // TODO: Currently there's no interface for asking descendents. They'll still // have the same offset (relative to their parent) after moving. The only thing // we really have to ask is whether they need to be unmounted. return true; }
// CanSetName bool BPartition::CanSetName() const { BPartition* parent = Parent(); if (!parent || !fDelegate) return false; return parent->_SupportsChildOperation(this, B_DISK_SYSTEM_SUPPORTS_SETTING_NAME); }
// CanSetType bool BPartition::CanSetType() const { BPartition* parent = Parent(); if (!parent) return false; return parent->_SupportsChildOperation(this, B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE); }
// CanEditParameters bool BPartition::CanEditParameters() const { BPartition* parent = Parent(); if (!parent) return false; return parent->_SupportsChildOperation(this, B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS); }
// DeleteChild status_t BPartition::DeleteChild(int32 index) { if (!fDelegate) return B_NO_INIT; BPartition* child = ChildAt(index); if (!child || child->Parent() != this) return B_BAD_VALUE; return fDelegate->DeleteChild(child->fDelegate); }
BPartition* BImage::getFullPartition() { BPartition* ret = new BPartition(this); for (int x=0; x<myWidth; x++) { for (int y=0; y<myHeight; y++) { // setPixelOwner(x,y,ret,1); ret->addPixelFromSrc(x,y); } } return ret; }
// _Update status_t BPartition::_Update(user_partition_data* data, bool* updated) { user_partition_data* oldData = fPartitionData; fPartitionData = data; // check for changes if (data->offset != oldData->offset || data->size != oldData->size || data->block_size != oldData->block_size || data->status != oldData->status || data->flags != oldData->flags || data->volume != oldData->volume || data->disk_system != oldData->disk_system // not needed || compare_string(data->name, oldData->name) || compare_string(data->content_name, oldData->content_name) || compare_string(data->type, oldData->type) || compare_string(data->content_type, oldData->content_type) || compare_string(data->parameters, oldData->parameters) || compare_string(data->content_parameters, oldData->content_parameters)) { *updated = true; } // add new children and update existing ones status_t error = B_OK; for (int32 i = 0; i < data->child_count; i++) { user_partition_data* childData = data->children[i]; BPartition* child = (BPartition*)childData->user_data; if (child) { // old partition error = child->_Update(childData, updated); if (error != B_OK) return error; } else { // new partition *updated = true; child = new(nothrow) BPartition; if (!child) return B_NO_MEMORY; error = child->_SetTo(fDevice, this, childData); if (error != B_OK) { delete child; return error; } childData->user_data = child; } } return error; }
// CanResize bool BPartition::CanResize(bool* canResizeContents, bool* whileMounted) const { BPartition* parent = Parent(); if (!parent) return false; if (!parent->_SupportsChildOperation(this, B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD)) { return false; } if (!_HasContent()) return true; return _SupportsOperation(B_DISK_SYSTEM_SUPPORTS_RESIZING, B_DISK_SYSTEM_SUPPORTS_RESIZING_WHILE_MOUNTED, whileMounted); }
void AutoMounter::_UnmountAndEjectVolume(BMessage* message) { int32 id; if (message->FindInt32("id", &id) == B_OK) { BDiskDeviceRoster roster; BPartition *partition; BDiskDevice device; if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) return; BPath path; if (partition->GetMountPoint(&path) == B_OK) _UnmountAndEjectVolume(partition, path, partition->ContentName()); } else { // see if we got a dev_t dev_t device; if (message->FindInt32("device_id", &device) != B_OK) return; BVolume volume(device); status_t status = volume.InitCheck(); char name[B_FILE_NAME_LENGTH]; if (status == B_OK) status = volume.GetName(name); if (status < B_OK) snprintf(name, sizeof(name), "device:%" B_PRIdDEV, device); BPath path; if (status == B_OK) { BDirectory mountPoint; status = volume.GetRootDirectory(&mountPoint); if (status == B_OK) status = path.SetTo(&mountPoint, "."); } if (status == B_OK) _UnmountAndEjectVolume(NULL, path, name); } }
void InstallerWindow::_PublishPackages() { fPackagesView->Clean(); PartitionMenuItem *item = (PartitionMenuItem *)fSrcMenu->FindMarked(); if (!item) return; BPath directory; BDiskDeviceRoster roster; BDiskDevice device; BPartition *partition; if (roster.GetPartitionWithID(item->ID(), &device, &partition) == B_OK) { if (partition->GetMountPoint(&directory) != B_OK) return; } else if (roster.GetDeviceWithID(item->ID(), &device) == B_OK) { if (device.GetMountPoint(&directory) != B_OK) return; } else return; // shouldn't happen directory.Append(PACKAGES_DIRECTORY); BDirectory dir(directory.Path()); if (dir.InitCheck() != B_OK) return; BEntry packageEntry; BList packages; while (dir.GetNextEntry(&packageEntry) == B_OK) { Package* package = Package::PackageFromEntry(packageEntry); if (package != NULL) packages.AddItem(package); } packages.SortItems(_ComparePackages); fPackagesView->AddPackages(packages, new BMessage(PACKAGE_CHECKBOX)); PostMessage(PACKAGE_CHECKBOX); }
void MainWindow::_Unmount(BDiskDevice* disk, partition_id selectedPartition) { if (!disk || selectedPartition < 0) { _DisplayPartitionError(B_TRANSLATE("You need to select a partition " "entry from the list.")); return; } BPartition* partition = disk->FindDescendant(selectedPartition); if (!partition) { _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " "partition by ID.")); return; } if (partition->IsMounted()) { BPath path; partition->GetMountPoint(&path); status_t ret = partition->Unmount(); if (ret < B_OK) { _DisplayPartitionError( B_TRANSLATE("Could not unmount partition %s."), partition, ret); } else { if (dev_for_path(path.Path()) == dev_for_path("/")) rmdir(path.Path()); // successful unmount, adapt to the changes _ScanDrives(); } } else { _DisplayPartitionError( B_TRANSLATE("The partition %s is already unmounted."), partition); } }
// _RemoveObsoleteDescendants status_t BPartition::_RemoveObsoleteDescendants(user_partition_data* data, bool* updated) { // remove all children not longer persistent // Not exactly efficient: O(n^2), considering BList::RemoveItem() // O(1). We could do better (O(n*log(n))), when sorting the arrays before, // but then the list access is more random and we had to find the // BPartition to remove, which makes the list operation definitely O(n). int32 count = CountChildren(); for (int32 i = count - 1; i >= 0; i--) { BPartition* child = ChildAt(i); bool found = false; for (int32 k = data->child_count - 1; k >= 0; k--) { if (data->children[k]->id == child->ID()) { // found partition: ask it to remove its obsolete descendants found = true; status_t error = child->_RemoveObsoleteDescendants( data->children[k], updated); if (error != B_OK) return error; // set the user data to the BPartition object to find it // quicker later data->children[k]->user_data = child; break; } } // if partition is obsolete, remove it if (!found) { *updated = true; _RemoveChild(i); } } return B_OK; }
int main(int argc, char** argv) { dev_t volumeDevice = dev_for_path("."); uint32 isVolumeFlags = 0; fs_info volumeInfo; bool doPartitionReadOnlyCheck = false; for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "--help")) { usage(); return 0; } if (argv[i][0] == '-') { if (strcmp(argv[i], "-readonly") == 0) isVolumeFlags |= B_FS_IS_READONLY; else if (strcmp(argv[i], "-query") == 0) isVolumeFlags |= B_FS_HAS_QUERY; else if (strcmp(argv[i], "-attribute") == 0) isVolumeFlags |= B_FS_HAS_ATTR; else if (strcmp(argv[i], "-mime") == 0) isVolumeFlags |= B_FS_HAS_MIME; else if (strcmp(argv[i], "-shared") == 0) isVolumeFlags |= B_FS_IS_SHARED; else if (strcmp(argv[i], "-persistent") == 0) isVolumeFlags |= B_FS_IS_PERSISTENT; else if (strcmp(argv[i], "-removable") == 0) isVolumeFlags |= B_FS_IS_REMOVABLE; else if (strcmp(argv[i], "-readonly-partion")) doPartitionReadOnlyCheck = true; else { fprintf(stderr, "%s: option %s is not understood (use --help for help)\n", argv[0], argv[i]); return 1; } } else { volumeDevice = dev_for_path(argv[i]); if (volumeDevice < 0) { fprintf(stderr, "%s: can't get information about volume: %s\n", argv[0], argv[i]); return 1; } } } if (doPartitionReadOnlyCheck) { // This requires an extra code-path, because volumes may now appear // writable, but only because of the "write" file-system overlay. BVolume volume(volumeDevice); status_t ret = volume.InitCheck(); if (ret != B_OK) { fprintf(stderr, "%s: failed to get BVolume for device %ld: %s\n", argv[0], volumeDevice, strerror(ret)); return 1; } BDiskDeviceRoster roster; BDiskDevice diskDevice; BPartition* partition; ret = roster.FindPartitionByVolume(volume, &diskDevice, &partition); if (ret != B_OK) { fprintf(stderr, "%s: failed to get partition for device %ld: %s\n", argv[0], volumeDevice, strerror(ret)); return 1; } // check this option directly and not via fs_stat_dev() if (partition->IsReadOnly()) { printf("yes\n"); return 0; } } if (fs_stat_dev(volumeDevice, &volumeInfo) == B_OK) { if (volumeInfo.flags & isVolumeFlags) printf("yes\n"); else printf("no\n"); return 0; } else { fprintf(stderr, "%s: can't get information about dev_t: %ld\n", argv[0], volumeDevice); return 1; } }
int main(int argc, char** argv) { const struct option kLongOptions[] = { { "help", 0, NULL, 'h' }, { "check-only", 0, NULL, 'c' }, { NULL, 0, NULL, 0 } }; const char* kShortOptions = "hc"; // parse argument list bool checkOnly = false; while (true) { int nextOption = getopt_long(argc, argv, kShortOptions, kLongOptions, NULL); if (nextOption == -1) break; switch (nextOption) { case 'h': // --help usage(stdout); return 0; case 'c': // --check-only checkOnly = true; break; default: // everything else usage(stderr); return 1; } } // the device name should be the only non-option element if (optind != argc - 1) { usage(stderr); return 1; } const char* path = argv[optind]; //UnregisterFileDevice unregisterFileDevice; BDiskDeviceRoster roster; BPartition* partition; BDiskDevice device; status_t status = roster.GetPartitionForPath(path, &device, &partition); if (status != B_OK) { if (strncmp(path, "/dev", 4)) { // try mounted volume status = roster.FindPartitionByMountPoint(path, &device, &partition) ? B_OK : B_BAD_VALUE; } // TODO: try to register file device if (status != B_OK) { fprintf(stderr, "%s: Failed to get disk device for path \"%s\": " "%s\n", kProgramName, path, strerror(status)); return 1; } } // Prepare the device for modifications status = device.PrepareModifications(); if (status != B_OK) { fprintf(stderr, "%s: Could not prepare the device for modifications: " "%s\n", kProgramName, strerror(status)); return 1; } // Check if the partition supports repairing bool canRepairWhileMounted; bool canRepair = partition->CanRepair(checkOnly, &canRepairWhileMounted); if (!canRepair && !canRepairWhileMounted) { fprintf(stderr, "%s: The disk system does not support repairing.\n", kProgramName); return 1; } if (partition->IsMounted() && !canRepairWhileMounted) { fprintf(stderr, "%s: The disk system does not support repairing a " "mounted volume.\n", kProgramName); return 1; } if (!partition->IsMounted() && !canRepair) { fprintf(stderr, "%s: The disk system does not support repairing a " "volume that is not mounted.\n", kProgramName); return 1; } BDiskSystem diskSystem; status = partition->GetDiskSystem(&diskSystem); if (status != B_OK) { fprintf(stderr, "%s: Failed to get disk system for partition: %s\n", kProgramName, strerror(status)); return 1; } // Repair the volume status = partition->Repair(checkOnly); if (status != B_OK) { fprintf(stderr, "%s: Repairing failed: %s\n", kProgramName, strerror(status)); return 1; } status = device.CommitModifications(); return 0; }
void MainWindow::_UpdateMenus(BDiskDevice* disk, partition_id selectedPartition, partition_id parentID) { while (BMenuItem* item = fFormatMenu->RemoveItem(0L)) delete item; while (BMenuItem* item = fDiskInitMenu->RemoveItem(0L)) delete item; fCreateMI->SetEnabled(false); fUnmountMI->SetEnabled(false); fDiskInitMenu->SetEnabled(false); fFormatMenu->SetEnabled(false); if (!disk) { fWipeMI->SetEnabled(false); fEjectMI->SetEnabled(false); fSurfaceTestMI->SetEnabled(false); } else { // fWipeMI->SetEnabled(true); fWipeMI->SetEnabled(false); fEjectMI->SetEnabled(disk->IsRemovableMedia()); // fSurfaceTestMI->SetEnabled(true); fSurfaceTestMI->SetEnabled(false); // Create menu and items BPartition* parentPartition = NULL; if (selectedPartition <= -2) { // a partitionable space item is selected parentPartition = disk->FindDescendant(parentID); } if (parentPartition && parentPartition->ContainsPartitioningSystem()) fCreateMI->SetEnabled(true); bool prepared = disk->PrepareModifications() == B_OK; fFormatMenu->SetEnabled(prepared); fDeleteMI->SetEnabled(prepared); BPartition* partition = disk->FindDescendant(selectedPartition); BDiskSystem diskSystem; fDDRoster.RewindDiskSystems(); while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { if (!diskSystem.SupportsInitializing()) continue; BMessage* message = new BMessage(MSG_INITIALIZE); message->AddInt32("parent id", parentID); message->AddString("disk system", diskSystem.PrettyName()); BString label = diskSystem.PrettyName(); label << B_UTF8_ELLIPSIS; BMenuItem* item = new BMenuItem(label.String(), message); // TODO: Very unintuitive that we have to use PrettyName (vs Name) item->SetEnabled(partition != NULL && partition->CanInitialize(diskSystem.PrettyName())); if (disk->ID() == selectedPartition && !diskSystem.IsFileSystem()) { // Disk is selected, and DiskSystem is a partition map fDiskInitMenu->AddItem(item); } else if (diskSystem.IsFileSystem()) { // Otherwise a filesystem fFormatMenu->AddItem(item); } } // Mount items if (partition) { fFormatMenu->SetEnabled(!partition->IsMounted() && !partition->IsReadOnly() && partition->Device()->HasMedia() && fFormatMenu->CountItems() > 0); fDiskInitMenu->SetEnabled(!partition->IsMounted() && !partition->IsReadOnly() && partition->Device()->HasMedia() && partition->IsDevice() && fDiskInitMenu->CountItems() > 0); fDeleteMI->SetEnabled(!partition->IsMounted() && !partition->IsDevice()); fMountMI->SetEnabled(!partition->IsMounted()); bool unMountable = false; if (partition->IsMounted()) { // see if this partition is the boot volume BVolume volume; BVolume bootVolume; if (BVolumeRoster().GetBootVolume(&bootVolume) == B_OK && partition->GetVolume(&volume) == B_OK) { unMountable = volume != bootVolume; } else unMountable = true; } fUnmountMI->SetEnabled(unMountable); } else { fDeleteMI->SetEnabled(false); fMountMI->SetEnabled(false); fFormatMenu->SetEnabled(false); fDiskInitMenu->SetEnabled(false); } if (prepared) disk->CancelModifications(); fMountAllMI->SetEnabled(true); } if (selectedPartition < 0) { fDeleteMI->SetEnabled(false); fMountMI->SetEnabled(false); } }
void MountVolume::ArgvReceived(int32 argc, char** argv) { MountVisitor mountVisitor; PrintPartitionsVisitor printPartitionsVisitor; bool listAllDevices = false; if (argc < 2) printPartitionsVisitor.listMountablePartitions = true; // parse arguments for (int argi = 1; argi < argc; argi++) { const char* arg = argv[argi]; if (arg[0] != '\0' && arg[0] != '-') { mountVisitor.toMount.insert(arg); } else if (strcmp(arg, "-s") == 0) { mountVisitor.silent = true; } else if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { print_usage_and_exit(false); } else if (strcmp(arg, "-all") == 0) { mountVisitor.mountAll = true; } else if (strcmp(arg, "-allbfs") == 0) { mountVisitor.mountBFS = true; } else if (strcmp(arg, "-allhfs") == 0) { mountVisitor.mountHFS = true; } else if (strcmp(arg, "-alldos") == 0) { mountVisitor.mountDOS = true; } else if (strcmp(arg, "-ro") == 0 || strcmp(arg, "-readonly") == 0) { mountVisitor.readOnly = true; } else if (strcmp(arg, "-u") == 0 || strcmp(arg, "-unmount") == 0) { argi++; if (argi >= argc) print_usage_and_exit(true); mountVisitor.toUnmount.insert(argv[argi]); } else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-l") == 0) { printPartitionsVisitor.listMountablePartitions = true; } else if (strcmp(arg, "-lh") == 0) { printPartitionsVisitor.listAllPartitions = true; } else if (strcmp(arg, "-dd") == 0) { listAllDevices = true; } else if (strcmp(arg, "-r") == 0 || strcmp(arg, "-publishall") == 0 || strcmp(arg, "-publishbfs") == 0 || strcmp(arg, "-publishhfs") == 0 || strcmp(arg, "-publishdos") == 0) { // obsolete: ignore } else print_usage_and_exit(true); } // get a disk device list BDiskDeviceList deviceList; status_t error = deviceList.Fetch(); if (error != B_OK) { fprintf(stderr, "Failed to get the list of disk devices: %s", strerror(error)); exit(1); } // mount/unmount volumes deviceList.VisitEachMountablePartition(&mountVisitor); BDiskDeviceRoster roster; // try mount file images for (StringSet::iterator iterator = mountVisitor.toMount.begin(); iterator != mountVisitor.toMount.end();) { const char* name = (*iterator).c_str(); iterator++; BEntry entry(name, true); if (!entry.Exists()) continue; // TODO: improve error messages BPath path; if (entry.GetPath(&path) != B_OK) continue; partition_id id = -1; BDiskDevice device; BPartition* partition; if (!strncmp(path.Path(), "/dev/", 5)) { // seems to be a device path if (roster.GetPartitionForPath(path.Path(), &device, &partition) != B_OK) continue; } else { // a file with this name exists, so try to mount it id = roster.RegisterFileDevice(path.Path()); if (id < 0) continue; if (roster.GetPartitionWithID(id, &device, &partition) != B_OK) { roster.UnregisterFileDevice(id); continue; } } status_t status = partition->Mount(NULL, mountVisitor.readOnly ? B_MOUNT_READ_ONLY : 0); if (!mountVisitor.silent) { if (status >= B_OK) { BPath mountPoint; partition->GetMountPoint(&mountPoint); printf("%s \"%s\" mounted successfully at \"%s\".\n", id < 0 ? "Device" : "Image", name, mountPoint.Path()); } } if (status >= B_OK) { // remove from list mountVisitor.toMount.erase(name); } else if (id >= 0) roster.UnregisterFileDevice(id); } // TODO: support unmounting images by path! // print errors for the volumes to mount/unmount, that weren't found if (!mountVisitor.silent) { for (StringSet::iterator it = mountVisitor.toMount.begin(); it != mountVisitor.toMount.end(); it++) { fprintf(stderr, "Failed to mount volume `%s': Volume not found.\n", (*it).c_str()); } for (StringSet::iterator it = mountVisitor.toUnmount.begin(); it != mountVisitor.toUnmount.end(); it++) { fprintf(stderr, "Failed to unmount volume `%s': Volume not " "found.\n", (*it).c_str()); } } // update the disk device list error = deviceList.Fetch(); if (error != B_OK) { fprintf(stderr, "Failed to update the list of disk devices: %s", strerror(error)); exit(1); } // print information if (listAllDevices) { // TODO } // determine width of the terminal in order to shrink the columns if needed if (isatty(STDOUT_FILENO)) { winsize size; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size, sizeof(winsize)) == 0) { if (size.ws_col < 95) { sVolumeNameWidth -= (95 - size.ws_col) / 2; sFSNameWidth -= (95 - size.ws_col) / 2; } } } if (printPartitionsVisitor.IsUsed()) { printf("%-*s %-*s Size Mounted At (Device)\n", sVolumeNameWidth, "Volume", sFSNameWidth, "File System"); BString separator; separator.SetTo('-', sVolumeNameWidth + sFSNameWidth + 35); puts(separator.String()); if (printPartitionsVisitor.listAllPartitions) deviceList.VisitEachPartition(&printPartitionsVisitor); else deviceList.VisitEachMountablePartition(&printPartitionsVisitor); } exit(0); }
void MainWindow::_Create(BDiskDevice* disk, partition_id selectedPartition) { if (!disk || selectedPartition > -2) { _DisplayPartitionError(B_TRANSLATE("The currently selected partition " "is not empty.")); return; } if (disk->IsReadOnly()) { _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); return; } PartitionListRow* currentSelection = dynamic_cast<PartitionListRow*>( fListView->CurrentSelection()); if (!currentSelection) { _DisplayPartitionError(B_TRANSLATE("There was an error acquiring the " "partition row.")); return; } BPartition* parent = disk->FindDescendant(currentSelection->ParentID()); if (!parent) { _DisplayPartitionError(B_TRANSLATE("The currently selected partition " "does not have a parent partition.")); return; } if (!parent->ContainsPartitioningSystem()) { _DisplayPartitionError(B_TRANSLATE("The selected partition does not " "contain a partitioning system.")); return; } ModificationPreparer modificationPreparer(disk); status_t ret = modificationPreparer.ModificationStatus(); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " "disk for modifications."), NULL, ret); return; } // get partitioning info BPartitioningInfo partitioningInfo; status_t error = parent->GetPartitioningInfo(&partitioningInfo); if (error != B_OK) { _DisplayPartitionError(B_TRANSLATE("Could not aquire partitioning " "information.")); return; } int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); if (spacesCount == 0) { _DisplayPartitionError(B_TRANSLATE("There's no space on the partition " "where a child partition could be created.")); return; } BString name, type, parameters; off_t offset = currentSelection->Offset(); off_t size = currentSelection->Size(); CreateParamsPanel* panel = new CreateParamsPanel(this, parent, offset, size); if (panel->Go(offset, size, name, type, parameters) == GO_CANCELED) return; ret = parent->ValidateCreateChild(&offset, &size, type.String(), &name, parameters.String()); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Validation of the given creation " "parameters failed.")); return; } // Warn the user one more time... BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " "want to write the changes back to disk now?\n\n" "All data on the partition will be irretrievably lost if you do " "so!"), B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); int32 choice = alert->Go(); if (choice == 1) return; ret = parent->CreateChild(offset, size, type.String(), name.String(), parameters.String()); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Creation of the partition has " "failed.")); return; } // commit ret = modificationPreparer.CommitModifications(); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Failed to format the " "partition. No changes have been written to disk.")); return; } // The disk layout has changed, update disk information bool updated; ret = disk->Update(&updated); _ScanDrives(); fDiskView->ForceUpdate(); }
void MainWindow::_Initialize(BDiskDevice* disk, partition_id selectedPartition, const BString& diskSystemName) { if (!disk || selectedPartition < 0) { _DisplayPartitionError(B_TRANSLATE("You need to select a partition " "entry from the list.")); return; } if (disk->IsReadOnly()) { _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); return; } BPartition* partition = disk->FindDescendant(selectedPartition); if (!partition) { _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " "partition by ID.")); return; } if (partition->IsMounted()) { _DisplayPartitionError( B_TRANSLATE("The partition %s is currently mounted.")); // TODO: option to unmount and continue on success to unmount return; } BDiskSystem diskSystem; fDDRoster.RewindDiskSystems(); bool found = false; while (fDDRoster.GetNextDiskSystem(&diskSystem) == B_OK) { if (diskSystem.SupportsInitializing()) { if (diskSystemName == diskSystem.PrettyName()) { found = true; break; } } } char message[512]; if (!found) { snprintf(message, sizeof(message), B_TRANSLATE("Disk system \"%s\"\" " "not found!")); _DisplayPartitionError(message); return; } if (diskSystem.IsFileSystem()) { if (disk->ID() == selectedPartition) { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to format a raw disk? (most people initialize the disk " "with a partitioning system first) You will be asked " "again before changes are written to the disk.")); } else if (partition->ContentName() && strlen(partition->ContentName()) > 0) { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to format the partition \"%s\"? You will be asked " "again before changes are written to the disk."), partition->ContentName()); } else { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to format the partition? You will be asked again " "before changes are written to the disk.")); } } else { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to initialize the selected disk? All data will be lost. " "You will be asked again before changes are written to the " "disk.\n")); } BAlert* alert = new BAlert("first notice", message, B_TRANSLATE("Continue"), B_TRANSLATE("Cancel"), NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); int32 choice = alert->Go(); if (choice == 1) return; ModificationPreparer modificationPreparer(disk); status_t ret = modificationPreparer.ModificationStatus(); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " "disk for modifications."), NULL, ret); return; } BString name; BString parameters; // TODO: diskSystem.IsFileSystem() seems like a better fit here? if (diskSystemName == "Be File System") { InitParamsPanel* panel = new InitParamsPanel(this, diskSystemName, partition); if (panel->Go(name, parameters) == GO_CANCELED) return; } else if (diskSystemName == "Intel Partition Map") { // TODO: parameters? } else if (diskSystemName == "Intel Extended Partition") { // TODO: parameters? } bool supportsName = diskSystem.SupportsContentName(); BString validatedName(name); ret = partition->ValidateInitialize(diskSystem.PrettyName(), supportsName ? &validatedName : NULL, parameters.String()); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Validation of the given " "initialization parameters failed."), partition, ret); return; } BString previousName = partition->ContentName(); ret = partition->Initialize(diskSystem.PrettyName(), supportsName ? validatedName.String() : NULL, parameters.String()); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Initialization of the partition " "%s failed. (Nothing has been written to disk.)"), partition, ret); return; } // everything looks fine, we are ready to actually write the changes // to disk // Warn the user one more time... if (previousName.Length() > 0) { if (partition->IsDevice()) { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to write the changes back to disk now?\n\n" "All data on the disk %s will be irretrievably lost if you " "do so!"), previousName.String()); } else { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to write the changes back to disk now?\n\n" "All data on the partition %s will be irretrievably lost if you " "do so!"), previousName.String()); } } else { if (partition->IsDevice()) { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to write the changes back to disk now?\n\n" "All data on the selected disk will be irretrievably lost if " "you do so!")); } else { snprintf(message, sizeof(message), B_TRANSLATE("Are you sure you " "want to write the changes back to disk now?\n\n" "All data on the selected partition will be irretrievably lost " "if you do so!")); } } alert = new BAlert("final notice", message, B_TRANSLATE("Write changes"), B_TRANSLATE("Cancel"), NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); choice = alert->Go(); if (choice == 1) return; // commit ret = modificationPreparer.CommitModifications(); // The partition pointer is toast now! Use the partition ID to // retrieve it again. partition = disk->FindDescendant(selectedPartition); if (ret == B_OK) { if (diskSystem.IsFileSystem()) { _DisplayPartitionError(B_TRANSLATE("The partition %s has been " "successfully formatted.\n"), partition); } else { _DisplayPartitionError(B_TRANSLATE("The disk has been " "successfully initialized.\n"), partition); } } else { if (diskSystem.IsFileSystem()) { _DisplayPartitionError(B_TRANSLATE("Failed to format the " "partition %s!\n"), partition, ret); } else { _DisplayPartitionError(B_TRANSLATE("Failed to initialize the " "disk %s!\n"), partition, ret); } } _ScanDrives(); }
virtual bool Visit(BPartition* partition, int32 level) { if (fOnlyOnDeviceID >= 0) { // only mount partitions on the given device id // or if the partition ID is already matched BPartition* device = partition; while (device->Parent() != NULL) { if (device->ID() == fOnlyOnDeviceID) { // we are happy break; } device = device->Parent(); } if (device->ID() != fOnlyOnDeviceID) return false; } mount_mode mode = !fInitialRescan && partition->Device()->IsRemovableMedia() ? fRemovableMode : fNormalMode; if (mode == kNoVolumes || partition->IsMounted() || !partition->ContainsFileSystem()) return false; BPath path; if (partition->GetPath(&path) != B_OK) return false; if (mode == kRestorePreviousVolumes) { // mount all volumes that were stored in the settings file const char *volumeName = NULL; if (partition->ContentName() == NULL || fPrevious.FindString(path.Path(), &volumeName) != B_OK || strcmp(volumeName, partition->ContentName())) return false; } else if (mode == kOnlyBFSVolumes) { if (partition->ContentType() == NULL || strcmp(partition->ContentType(), kPartitionTypeBFS)) return false; } uint32 mountFlags; if (!fInitialRescan) { // Ask the user about mount flags if this is not the // initial scan. if (!_SuggestMountFlags(partition, &mountFlags)) return false; } else { BString mountFlagsKey(path.Path()); mountFlagsKey << kMountFlagsKeyExtension; if (fPrevious.FindInt32(mountFlagsKey.String(), (int32*)&mountFlags) < B_OK) { mountFlags = 0; } } if (partition->Mount(NULL, mountFlags) != B_OK) { // TODO: Error to syslog } return false; }
void _NewPartition() { if (!fPrepared) { if (fDevice->IsReadOnly()) printf("Device is read-only!\n"); else printf("Sorry, not prepared for modifications!\n"); return; } // get the parent partition BPartition* partition = NULL; int32 partitionIndex; if (!_SelectPartition("parent partition index [-1 to abort]: ", partition, partitionIndex)) { return; } printf("\nselected partition:\n\n"); print_partition_table_header(); print_partition(partition, 0, partitionIndex); if (!partition->ContainsPartitioningSystem()) { printf("The selected partition does not contain a partitioning " "system.\n"); return; } // get supported types BObjectList<BString> supportedTypes(20, true); BString typeBuffer; int32 cookie = 0; while (partition->GetNextSupportedChildType(&cookie, &typeBuffer) == B_OK) { supportedTypes.AddItem(new BString(typeBuffer)); } if (supportedTypes.IsEmpty()) { printf("The partitioning system is not able to create any " "child partition (no supported types).\n"); return; } // get partitioning info BPartitioningInfo partitioningInfo; status_t error = partition->GetPartitioningInfo(&partitioningInfo); if (error != B_OK) { printf("Failed to get partitioning info for partition: %s\n", strerror(error)); return; } int32 spacesCount = partitioningInfo.CountPartitionableSpaces(); if (spacesCount == 0) { printf("There's no space on the partition where a child partition " "could be created\n"); return; } // let the user select the partition type, if there's more than one int64 typeIndex = 0; int32 supportedTypesCount = supportedTypes.CountItems(); if (supportedTypesCount > 1) { // list them printf("Possible partition types:\n"); for (int32 i = 0; i < supportedTypesCount; i++) printf("%2ld %s\n", i, supportedTypes.ItemAt(i)->String()); if (!_ReadNumber("supported type index [-1 to abort]: ", 0, supportedTypesCount - 1, -1, "invalid index", typeIndex)) { return; } } const char* type = supportedTypes.ItemAt(typeIndex)->String(); // list partitionable spaces printf("Unused regions where the new partition could be created:\n"); for (int32 i = 0; i < spacesCount; i++) { off_t _offset; off_t _size; partitioningInfo.GetPartitionableSpaceAt(i, &_offset, &_size); BString offset, size; get_size_string(_offset, offset); get_size_string(_size, size); printf("%2ld start: %8s, size: %8s\n", i, offset.String(), size.String()); } // let the user select the partitionable space, if there's more than one int64 spaceIndex = 0; if (spacesCount > 1) { if (!_ReadNumber("unused region index [-1 to abort]: ", 0, spacesCount - 1, -1, "invalid index", spaceIndex)) { return; } } off_t spaceOffset; off_t spaceSize; partitioningInfo.GetPartitionableSpaceAt(spaceIndex, &spaceOffset, &spaceSize); off_t start; off_t size; BString parameters; while (true) { // let the user enter start, size, and parameters // start while (true) { BString spaceOffsetString; get_size_string(spaceOffset, spaceOffsetString); BString prompt("partition start [default: "); prompt << spaceOffsetString << "]: "; if (!_ReadSize(prompt.String(), spaceOffset, start)) return; if (start >= spaceOffset && start <= spaceOffset + spaceSize) break; printf("invalid partition start\n"); } // size off_t maxSize = spaceOffset + spaceSize - start; while (true) { BString maxSizeString; get_size_string(maxSize, maxSizeString); BString prompt("partition size [default: "); prompt << maxSizeString << "]: "; if (!_ReadSize(prompt.String(), maxSize, size)) return; if (size >= 0 && start + size <= spaceOffset + spaceSize) break; printf("invalid partition size\n"); } // parameters if (!_ReadLine("partition parameters: ", parameters)) return; // validate parameters off_t validatedStart = start; off_t validatedSize = size; // TODO: Support the name parameter! if (partition->ValidateCreateChild(&start, &size, type, NULL, parameters.String()) != B_OK) { printf("Validation of the given values failed. Sorry, can't " "continue.\n"); return; } // did the disk system change offset or size? if (validatedStart == start && validatedSize == size) { printf("Everything looks dandy.\n"); } else { BString startString, sizeString; get_size_string(validatedStart, startString); get_size_string(validatedSize, sizeString); printf("The disk system adjusted the partition start and " "size to %lld (%s) and %lld (%s).\n", validatedStart, startString.String(), validatedSize, sizeString.String()); start = validatedStart; size = validatedSize; } // let the user decide whether to continue, change parameters, or // abort bool changeParameters = false; while (true) { BString line; _ReadLine("[c]ontinue, change [p]arameters, or [a]bort? ", line); if (line == "a") return; if (line == "p") { changeParameters = true; break; } if (line == "c") break; printf("invalid input\n"); } if (!changeParameters) break; } // create child error = partition->CreateChild(start, size, type, NULL, parameters.String()); if (error != B_OK) printf("Creating the partition failed: %s\n", strerror(error)); }
void _InitializePartition() { if (!fPrepared) { if (fDevice->IsReadOnly()) printf("Device is read-only!\n"); else printf("Sorry, not prepared for modifications!\n"); return; } // get the partition int32 partitionIndex; BPartition* partition = NULL; if (!_SelectPartition("partition index [-1 to abort]: ", partition, partitionIndex)) { return; } printf("\nselected partition:\n\n"); print_partition_table_header(); print_partition(partition, 0, partitionIndex); // get available disk systems BObjectList<BDiskSystem> diskSystems(20, true); BDiskDeviceRoster roster; { BDiskSystem diskSystem; while (roster.GetNextDiskSystem(&diskSystem) == B_OK) { if (partition->CanInitialize(diskSystem.PrettyName())) diskSystems.AddItem(new BDiskSystem(diskSystem)); } } if (diskSystems.IsEmpty()) { printf("There are no disk systems, that can initialize this " "partition.\n"); return; } // print the available disk systems printf("\ndisk systems that can initialize the selected partition:\n"); for (int32 i = 0; BDiskSystem* diskSystem = diskSystems.ItemAt(i); i++) printf("%2ld %s\n", i, diskSystem->PrettyName()); printf("\n"); // get the disk system int64 diskSystemIndex; if (!_ReadNumber("disk system index [-1 to abort]: ", 0, diskSystems.CountItems() - 1, -1, "invalid index", diskSystemIndex)) { return; } BDiskSystem* diskSystem = diskSystems.ItemAt(diskSystemIndex); bool supportsName = diskSystem->SupportsContentName(); BString name; BString parameters; while (true) { // let the user enter name and parameters if (supportsName && !_ReadLine("partition name: ", name) || !_ReadLine("partition parameters: ", parameters)) { return; } // validate parameters BString validatedName(name); if (partition->ValidateInitialize(diskSystem->PrettyName(), supportsName ? &validatedName : NULL, parameters.String()) != B_OK) { printf("Validation of the given values failed. Sorry, can't " "continue.\n"); return; } // did the disk system change the name? if (!supportsName || name == validatedName) { printf("Everything looks dandy.\n"); } else { printf("The disk system adjusted the file name to \"%s\".\n", validatedName.String()); name = validatedName; } // let the user decide whether to continue, change parameters, or // abort bool changeParameters = false; while (true) { BString line; _ReadLine("[c]ontinue, change [p]arameters, or [a]bort? ", line); if (line == "a") return; if (line == "p") { changeParameters = true; break; } if (line == "c") break; printf("invalid input\n"); } if (!changeParameters) break; } // initialize status_t error = partition->Initialize(diskSystem->PrettyName(), supportsName ? name.String() : NULL, parameters.String()); if (error != B_OK) printf("Initialization failed: %s\n", strerror(error)); }
void WorkerThread::MessageReceived(BMessage* message) { CALLED(); switch (message->what) { case MSG_START_INSTALLING: _PerformInstall(fWindow->GetSourceMenu(), fWindow->GetTargetMenu()); break; case MSG_WRITE_BOOT_SECTOR: { int32 id; if (message->FindInt32("id", &id) != B_OK) { _SetStatusMessage(B_TRANSLATE("Boot sector not written " "because of an internal error.")); break; } // TODO: Refactor with _PerformInstall() BPath targetDirectory; BDiskDevice device; BPartition* partition; if (fDDRoster.GetPartitionWithID(id, &device, &partition) == B_OK) { if (!partition->IsMounted()) { if (partition->Mount() < B_OK) { _SetStatusMessage(B_TRANSLATE("The partition can't be " "mounted. Please choose a different partition.")); break; } } if (partition->GetMountPoint(&targetDirectory) != B_OK) { _SetStatusMessage(B_TRANSLATE("The mount point could not " "be retrieved.")); break; } } else if (fDDRoster.GetDeviceWithID(id, &device) == B_OK) { if (!device.IsMounted()) { if (device.Mount() < B_OK) { _SetStatusMessage(B_TRANSLATE("The disk can't be " "mounted. Please choose a different disk.")); break; } } if (device.GetMountPoint(&targetDirectory) != B_OK) { _SetStatusMessage(B_TRANSLATE("The mount point could not " "be retrieved.")); break; } } _LaunchFinishScript(targetDirectory); // TODO: Get error from executing script! _SetStatusMessage( B_TRANSLATE("Boot sector successfully written.")); } default: BLooper::MessageReceived(message); } }
void MainWindow::_Delete(BDiskDevice* disk, partition_id selectedPartition) { if (!disk || selectedPartition < 0) { _DisplayPartitionError(B_TRANSLATE("You need to select a partition " "entry from the list.")); return; } if (disk->IsReadOnly()) { _DisplayPartitionError(B_TRANSLATE("The selected disk is read-only.")); return; } BPartition* partition = disk->FindDescendant(selectedPartition); if (!partition) { _DisplayPartitionError(B_TRANSLATE("Unable to find the selected " "partition by ID.")); return; } BPartition* parent = partition->Parent(); if (!parent) { _DisplayPartitionError(B_TRANSLATE("The currently selected partition " "does not have a parent partition.")); return; } ModificationPreparer modificationPreparer(disk); status_t ret = modificationPreparer.ModificationStatus(); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("There was an error preparing the " "disk for modifications."), NULL, ret); return; } if (!parent->CanDeleteChild(partition->Index())) { _DisplayPartitionError( B_TRANSLATE("Cannot delete the selected partition.")); return; } // Warn the user one more time... BAlert* alert = new BAlert("final notice", B_TRANSLATE("Are you sure you " "want to delete the selected partition?\n\n" "All data on the partition will be irretrievably lost if you " "do so!"), B_TRANSLATE("Delete partition"), B_TRANSLATE("Cancel"), NULL, B_WIDTH_FROM_WIDEST, B_WARNING_ALERT); int32 choice = alert->Go(); if (choice == 1) return; ret = parent->DeleteChild(partition->Index()); if (ret != B_OK) { _DisplayPartitionError( B_TRANSLATE("Could not delete the selected partition.")); return; } ret = modificationPreparer.CommitModifications(); if (ret != B_OK) { _DisplayPartitionError(B_TRANSLATE("Failed to delete the partition. " "No changes have been written to disk.")); return; } _ScanDrives(); fDiskView->ForceUpdate(); }
void WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu) { CALLED(); BPath targetDirectory; BPath srcDirectory; BPath trashPath; BPath testPath; BDirectory targetDir; BDiskDevice device; BPartition* partition; BVolume targetVolume; status_t err = B_OK; int32 entries = 0; entry_ref testRef; const char* mountError = B_TRANSLATE("The disk can't be mounted. Please " "choose a different disk."); BMessenger messenger(fWindow); ProgressReporter reporter(messenger, new BMessage(MSG_STATUS_MESSAGE)); CopyEngine engine(&reporter); BList unzipEngines; PartitionMenuItem* targetItem = (PartitionMenuItem*)targetMenu->FindMarked(); PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked(); if (!srcItem || !targetItem) { ERR("bad menu items\n"); goto error; } // check if target is initialized // ask if init or mount as is if (fDDRoster.GetPartitionWithID(targetItem->ID(), &device, &partition) == B_OK) { if (!partition->IsMounted()) { if ((err = partition->Mount()) < B_OK) { _SetStatusMessage(mountError); ERR("BPartition::Mount"); goto error; } } if ((err = partition->GetVolume(&targetVolume)) != B_OK) { ERR("BPartition::GetVolume"); goto error; } if ((err = partition->GetMountPoint(&targetDirectory)) != B_OK) { ERR("BPartition::GetMountPoint"); goto error; } } else if (fDDRoster.GetDeviceWithID(targetItem->ID(), &device) == B_OK) { if (!device.IsMounted()) { if ((err = device.Mount()) < B_OK) { _SetStatusMessage(mountError); ERR("BDiskDevice::Mount"); goto error; } } if ((err = device.GetVolume(&targetVolume)) != B_OK) { ERR("BDiskDevice::GetVolume"); goto error; } if ((err = device.GetMountPoint(&targetDirectory)) != B_OK) { ERR("BDiskDevice::GetMountPoint"); goto error; } } else goto error; // shouldn't happen // check if target has enough space if ((fSpaceRequired > 0 && targetVolume.FreeBytes() < fSpaceRequired) && ((new BAlert("", B_TRANSLATE("The destination disk may not have " "enough space. Try choosing a different disk or choose to not " "install optional items."), B_TRANSLATE("Try installing anyway"), B_TRANSLATE("Cancel"), 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { goto error; } if (fDDRoster.GetPartitionWithID(srcItem->ID(), &device, &partition) == B_OK) { if ((err = partition->GetMountPoint(&srcDirectory)) != B_OK) { ERR("BPartition::GetMountPoint"); goto error; } } else if (fDDRoster.GetDeviceWithID(srcItem->ID(), &device) == B_OK) { if ((err = device.GetMountPoint(&srcDirectory)) != B_OK) { ERR("BDiskDevice::GetMountPoint"); goto error; } } else goto error; // shouldn't happen // check not installing on itself if (strcmp(srcDirectory.Path(), targetDirectory.Path()) == 0) { _SetStatusMessage(B_TRANSLATE("You can't install the contents of a " "disk onto itself. Please choose a different disk.")); goto error; } // check not installing on boot volume if ((strncmp(BOOT_PATH, targetDirectory.Path(), strlen(BOOT_PATH)) == 0) && ((new BAlert("", B_TRANSLATE("Are you sure you want to install " "onto the current boot disk? The Installer will have to reboot " "your machine if you proceed."), B_TRANSLATE("OK"), B_TRANSLATE("Cancel"), 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { _SetStatusMessage("Installation stopped."); goto error; } // check if target volume's trash dir has anything in it // (target volume w/ only an empty trash dir is considered // an empty volume) if (find_directory(B_TRASH_DIRECTORY, &trashPath, false, &targetVolume) == B_OK && targetDir.SetTo(trashPath.Path()) == B_OK) { while (targetDir.GetNextRef(&testRef) == B_OK) { // Something in the Trash entries++; break; } } targetDir.SetTo(targetDirectory.Path()); // check if target volume otherwise has any entries while (entries == 0 && targetDir.GetNextRef(&testRef) == B_OK) { if (testPath.SetTo(&testRef) == B_OK && testPath != trashPath) entries++; } if (entries != 0 && ((new BAlert("", B_TRANSLATE("The target volume is not empty. Are " "you sure you want to install anyway?\n\nNote: The 'system' folder " "will be a clean copy from the source volume, all other folders " "will be merged, whereas files and links that exist on both the " "source and target volume will be overwritten with the source " "volume version."), B_TRANSLATE("Install anyway"), B_TRANSLATE("Cancel"), 0, B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { // TODO: Would be cool to offer the option here to clean additional // folders at the user's choice (like /boot/common and /boot/develop). err = B_CANCELED; goto error; } // Begin actual installation _LaunchInitScript(targetDirectory); // Create the default indices which should always be present on a proper // boot volume. We don't care if the source volume does not have them. // After all, the user might be re-installing to another drive and may // want problems fixed along the way... err = _CreateDefaultIndices(targetDirectory); if (err != B_OK) goto error; // Mirror all the indices which are present on the source volume onto // the target volume. err = _MirrorIndices(srcDirectory, targetDirectory); if (err != B_OK) goto error; // Let the engine collect information for the progress bar later on engine.ResetTargets(srcDirectory.Path()); err = engine.CollectTargets(srcDirectory.Path(), fCancelSemaphore); if (err != B_OK) goto error; // Collect selected packages also if (fPackages) { BPath pkgRootDir(srcDirectory.Path(), PACKAGES_DIRECTORY); int32 count = fPackages->CountItems(); for (int32 i = 0; i < count; i++) { Package *p = static_cast<Package*>(fPackages->ItemAt(i)); BPath packageDir(pkgRootDir.Path(), p->Folder()); err = engine.CollectTargets(packageDir.Path(), fCancelSemaphore); if (err != B_OK) goto error; } } // collect information about all zip packages err = _ProcessZipPackages(srcDirectory.Path(), targetDirectory.Path(), &reporter, unzipEngines); if (err != B_OK) goto error; reporter.StartTimer(); // copy source volume err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(), fCancelSemaphore); if (err != B_OK) goto error; // copy selected packages if (fPackages) { BPath pkgRootDir(srcDirectory.Path(), PACKAGES_DIRECTORY); int32 count = fPackages->CountItems(); for (int32 i = 0; i < count; i++) { Package *p = static_cast<Package*>(fPackages->ItemAt(i)); BPath packageDir(pkgRootDir.Path(), p->Folder()); err = engine.CopyFolder(packageDir.Path(), targetDirectory.Path(), fCancelSemaphore); if (err != B_OK) goto error; } } // Extract all zip packages. If an error occured, delete the rest of // the engines, but stop extracting. for (int32 i = 0; i < unzipEngines.CountItems(); i++) { UnzipEngine* engine = reinterpret_cast<UnzipEngine*>( unzipEngines.ItemAtFast(i)); if (err == B_OK) err = engine->UnzipPackage(); delete engine; } if (err != B_OK) goto error; _LaunchFinishScript(targetDirectory); BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED); return; error: BMessage statusMessage(MSG_RESET); if (err == B_CANCELED) _SetStatusMessage(B_TRANSLATE("Installation canceled.")); else statusMessage.AddInt32("error", err); ERR("_PerformInstall failed"); BMessenger(fWindow).SendMessage(&statusMessage); }
// main int main(int argc, const char *const *argv) { kArgc = argc; kArgv = argv; if (argc < 2) print_usage_and_exit(true); // parameters const char **files = new const char*[argc]; int fileCount = 0; bool dryRun = false; off_t startOffset = 0; // parse arguments for (int argi = 1; argi < argc;) { const char *arg = argv[argi++]; if (arg[0] == '-') { if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { print_usage_and_exit(false); } else if (strcmp(arg, "--dry-run") == 0) { dryRun = true; } else if (strcmp(arg, "-alert") == 0) { // ignore } else if (strcmp(arg, "-full") == 0) { // ignore } else if (strcmp(arg, "--start-offset") == 0) { if (argi >= argc) print_usage_and_exit(true); startOffset = strtoll(argv[argi++], NULL, 0); } else if (strcmp(arg, "-safe") == 0) { fprintf(stderr, "Error: Sorry, BeOS R3 isn't supported!\n"); exit(1); } else { print_usage_and_exit(true); } } else { files[fileCount++] = arg; } } // we need at least one file if (fileCount == 0) print_usage_and_exit(true); // read the boot code uint8 *bootCodeData = NULL; #ifndef __ANTARES__ bootCodeData = read_boot_code_data(argv[0]); #else image_info info; if (find_own_image(&info) == B_OK) bootCodeData = read_boot_code_data(info.name); #endif if (!bootCodeData) { fprintf(stderr, "Error: Failed to read \n"); exit(1); } // iterate through the files and make them bootable status_t error; for (int i = 0; i < fileCount; i++) { const char *fileName = files[i]; BEntry entry; error = entry.SetTo(fileName, true); if (error != B_OK) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(error)); exit(1); } // get stat to check the type of the file struct stat st; error = entry.GetStat(&st); if (error != B_OK) { fprintf(stderr, "Error: Failed to stat \"%s\": %s\n", fileName, strerror(error)); exit(1); } bool noPartition = false; int64 partitionOffset = 0; fs_info info; // needs to be here (we use the device name later) if (S_ISDIR(st.st_mode)) { #if defined(__BEOS__) || defined(__ANTARES__) // a directory: get the device error = fs_stat_dev(st.st_dev, &info); if (error != B_OK) { fprintf(stderr, "Error: Failed to determine device for " "\"%s\": %s\n", fileName, strerror(error)); exit(1); } fileName = info.device_name; #else (void)info; fprintf(stderr, "Error: Specifying directories not supported " "on this platform!\n"); exit(1); #endif } else if (S_ISREG(st.st_mode)) { // a regular file: fine noPartition = true; } else if (S_ISCHR(st.st_mode)) { // character special: a device or partition under BeOS // or under FreeBSD #if !(defined(__BEOS__) || defined(__ANTARES__)) && !defined(ANTARES_HOST_PLATFORM_FREEBSD) fprintf(stderr, "Error: Character special devices not " "supported on this platform.\n"); exit(1); #endif #ifdef ANTARES_HOST_PLATFORM_FREEBSD // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = -1; for (int k = fileNameLen - 1; k >= 0; k--) { if (!isdigit(fileName[k])) { baseNameLen = k + 1; break; } } // Remove de 's' from 'ad2s2' slice device (partition for DOS // users) to get 'ad2' base device baseNameLen--; if (baseNameLen < 0) { // only digits? fprintf(stderr, "Error: Failed to get base device name.\n"); exit(1); } if (baseNameLen < fileNameLen) { // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen + 1); // Don't forget the 's' of slice :) memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size int64 deviceSize; if (ioctl(baseFD, DIOCGMEDIASIZE, &deviceSize) == -1) { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! PartitionMapParser parser(baseFD, 0, deviceSize, 512); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #endif // ANTARES_HOST_PLATFORM_FREEBSD } else if (S_ISBLK(st.st_mode)) { // block device: a device or partition under Linux or Darwin #ifdef ANTARES_HOST_PLATFORM_LINUX // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = -1; for (int k = fileNameLen - 1; k >= 0; k--) { if (!isdigit(fileName[k])) { baseNameLen = k + 1; break; } } if (baseNameLen < 0) { // only digits? fprintf(stderr, "Error: Failed to get base device name.\n"); exit(1); } if (baseNameLen < fileNameLen) { // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen); memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size -- try BLKGETSIZE64, but, if it doesn't // work, fall back to the obsolete HDIO_GETGEO int64 deviceSize; hd_geometry geometry; if (ioctl(baseFD, BLKGETSIZE64, &deviceSize) == 0 && deviceSize > 0) { // looks good } else if (ioctl(baseFD, HDIO_GETGEO, &geometry) == 0) { deviceSize = (int64)geometry.heads * geometry.sectors * geometry.cylinders * 512; } else { fprintf(stderr, "Error: Failed to get device geometry " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // parse the partition map // TODO: block size! PartitionMapParser parser(baseFD, 0, deviceSize, 512); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); } else { // The given device is the base device. We'll write at // offset 0. } #elif defined(ANTARES_HOST_PLATFORM_DARWIN) // chop off the trailing number int fileNameLen = strlen(fileName); int baseNameLen = fileNameLen - 2; // get base device name and partition index char baseDeviceName[B_PATH_NAME_LENGTH]; int partitionIndex = atoi(fileName + baseNameLen + 1); memcpy(baseDeviceName, fileName, baseNameLen); baseDeviceName[baseNameLen] = '\0'; // open base device int baseFD = open(baseDeviceName, O_RDONLY); if (baseFD < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } // get device size int64 blockSize; int64 blockCount; int64 deviceSize; if (ioctl(baseFD, DKIOCGETBLOCKSIZE, &blockSize) == -1) { fprintf(stderr, "Error: Failed to get block size " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } if (ioctl(baseFD, DKIOCGETBLOCKCOUNT, &blockCount) == -1) { fprintf(stderr, "Error: Failed to get block count " "for \"%s\": %s\n", baseDeviceName, strerror(errno)); exit(1); } deviceSize = blockSize * blockCount; // parse the partition map PartitionMapParser parser(baseFD, 0, deviceSize, blockSize); PartitionMap map; error = parser.Parse(NULL, &map); if (error != B_OK) { fprintf(stderr, "Error: Parsing partition table on " "device \"%s\" failed: %s\n", baseDeviceName, strerror(error)); exit(1); } close(baseFD); // check the partition we are supposed to write at Partition *partition = map.PartitionAt(partitionIndex - 1); if (!partition || partition->IsEmpty()) { fprintf(stderr, "Error: Invalid partition index %d.\n", partitionIndex); dump_partition_map(map); exit(1); } if (partition->IsExtended()) { fprintf(stderr, "Error: Partition %d is an extended " "partition.\n", partitionIndex); dump_partition_map(map); exit(1); } partitionOffset = partition->Offset(); #else // partitions are block devices under Antares, but not under BeOS #ifndef __ANTARES__ fprintf(stderr, "Error: Block devices not supported on this " "platform!\n"); exit(1); #endif // __ANTARES__ #endif } else { fprintf(stderr, "Error: File type of \"%s\" is not supported.\n", fileName); exit(1); } // open the file int fd = open(fileName, O_RDWR); if (fd < 0) { fprintf(stderr, "Error: Failed to open \"%s\": %s\n", fileName, strerror(errno)); exit(1); } #if (defined(__BEOS__) || defined(__ANTARES__)) // get a partition info if (!noPartition && strlen(fileName) >= 3 && strncmp("raw", fileName + strlen(fileName) - 3, 3)) { partition_info partitionInfo; if (ioctl(fd, B_GET_PARTITION_INFO, &partitionInfo, sizeof(partitionInfo)) == 0) { partitionOffset = partitionInfo.offset; } else { fprintf(stderr, "Error: Failed to get partition info: %s\n", strerror(errno)); exit(1); } } #endif // __BEOS__ // adjust the partition offset in the boot code data // hard coded sector size: 512 bytes *(uint32*)(bootCodeData + kPartitionOffsetOffset) = B_HOST_TO_LENDIAN_INT32((uint32)(partitionOffset / 512)); // write the boot code printf("Writing boot code to \"%s\" (partition offset: %" B_PRId64 " bytes, start offset = %" B_PRIdOFF ") " "...\n", fileName, partitionOffset, startOffset); write_boot_code_part(fileName, fd, startOffset, bootCodeData, 0, kFirstBootCodePartSize, dryRun); write_boot_code_part(fileName, fd, startOffset, bootCodeData, kSecondBootCodePartOffset, kSecondBootCodePartSize, dryRun); #ifdef __ANTARES__ // check if this partition is mounted BDiskDeviceRoster roster; BPartition* partition; BDiskDevice device; status_t status = roster.GetPartitionForPath(fileName, &device, &partition); if (status != B_OK) { status = roster.GetFileDeviceForPath(fileName, &device); if (status == B_OK) partition = &device; } if (status == B_OK && partition->IsMounted() && !dryRun) { // This partition is mounted, we need to tell BFS to update its // boot block (we are using part of the same logical block). BPath path; status = partition->GetMountPoint(&path); if (status == B_OK) { update_boot_block update; update.offset = kSecondBootCodePartOffset - 512; update.data = bootCodeData + kSecondBootCodePartOffset; update.length = kSecondBootCodePartSize; int mountFD = open(path.Path(), O_RDONLY); if (ioctl(mountFD, BFS_IOCTL_UPDATE_BOOT_BLOCK, &update, sizeof(update_boot_block)) != 0) { fprintf(stderr, "Could not update BFS boot block: %s\n", strerror(errno)); } close(mountFD); } else { fprintf(stderr, "Could not update BFS boot code while the " "partition is mounted!\n"); } } #endif // __ANTARES__ close(fd); } return 0; }