/*! \brief Pre-order traverses the trees spanned by the BDiskDevices and their subobjects. The supplied visitor's Visit(BDiskDevice*) method is invoked for each disk device and Visit(BPartition*) for each (non-disk device) partition. If Visit() returns \c true, the iteration is terminated and this method returns \c true. If supplied, \a device is set to the concerned device and in \a partition the pointer to the partition object is returned. \param visitor The visitor. \param device Pointer to a pre-allocated BDiskDevice to be initialized to the device at which the iteration was terminated. May be \c NULL. \param partition Pointer to a pre-allocated BPartition pointer to be set to the partition at which the iteration was terminated. May be \c NULL. \return \c true, if the iteration was terminated, \c false otherwise. */ bool BDiskDeviceRoster::VisitEachPartition(BDiskDeviceVisitor* visitor, BDiskDevice* device, BPartition** partition) { bool terminatedEarly = false; if (visitor) { int32 oldCookie = fDeviceCookie; fDeviceCookie = 0; BDiskDevice deviceOnStack; BDiskDevice* useDevice = device ? device : &deviceOnStack; BPartition* foundPartition = NULL; while (GetNextDevice(useDevice) == B_OK) { foundPartition = useDevice->VisitEachDescendant(visitor); if (foundPartition) { terminatedEarly = true; break; } } fDeviceCookie = oldCookie; if (!terminatedEarly) useDevice->Unset(); else if (device && partition) *partition = foundPartition; } return terminatedEarly; }
void MainWindow::_SetToDiskAndPartition(partition_id disk, partition_id partition, partition_id parent) { //printf("MainWindow::_SetToDiskAndPartition(disk: %ld, partition: %ld, " // "parent: %ld)\n", disk, partition, parent); BDiskDevice* oldDisk = NULL; if (!fCurrentDisk || fCurrentDisk->ID() != disk) { oldDisk = fCurrentDisk; fCurrentDisk = NULL; if (disk >= 0) { BDiskDevice* newDisk = new BDiskDevice(); status_t ret = newDisk->SetTo(disk); if (ret < B_OK) { printf("error switching disks: %s\n", strerror(ret)); delete newDisk; } else fCurrentDisk = newDisk; } } fCurrentPartitionID = partition; fDiskView->SetDisk(fCurrentDisk, fCurrentPartitionID); _UpdateMenus(fCurrentDisk, fCurrentPartitionID, parent); delete oldDisk; }
/*! \brief Iterates through the all devices. The supplied visitor's Visit(BDiskDevice*) is invoked for each device. If Visit() returns \c true, the iteration is terminated and this method returns \c true. If supplied, \a device is set to the concerned device. \param visitor The visitor. \param device Pointer to a pre-allocated BDiskDevice to be initialized to the device at which the iteration was terminated. May be \c NULL. \return \c true, if the iteration was terminated, \c false otherwise. */ bool BDiskDeviceRoster::VisitEachDevice(BDiskDeviceVisitor* visitor, BDiskDevice* device) { bool terminatedEarly = false; if (visitor) { int32 oldCookie = fDeviceCookie; fDeviceCookie = 0; BDiskDevice deviceOnStack; BDiskDevice* useDevice = device ? device : &deviceOnStack; while (!terminatedEarly && GetNextDevice(useDevice) == B_OK) terminatedEarly = visitor->Visit(useDevice); fDeviceCookie = oldCookie; if (!terminatedEarly) useDevice->Unset(); } return terminatedEarly; }
DriveItem::DriveItem(const BDiskDevice& device, const BootMenuList& menus) : fBaselineOffset(0), fSizeWidth(0) { device.GetPath(&fPath); if (device.Name() != NULL && device.Name()[0]) fName = device.Name(); else if (strstr(fPath.Path(), "usb") != NULL) fName = B_TRANSLATE_COMMENT("USB Drive", "Default disk name"); else fName = B_TRANSLATE_COMMENT("Hard Drive", "Default disk name"); fIcon = new BBitmap(BRect(0, 0, B_LARGE_ICON - 1, B_LARGE_ICON - 1), B_RGBA32); if (device.GetIcon(fIcon, B_LARGE_ICON) != B_OK) memset(fIcon->Bits(), 0, fIcon->BitsLength()); fDrive = new BootDrive(fPath.Path()); fIsInstalled = fDrive->InstalledMenu(menus) != NULL; fCanBeInstalled = fDrive->CanMenuBeInstalled(menus); char buffer[256]; fSize = string_for_size(device.Size(), buffer, sizeof(buffer)); }
/*! Builds the list view items, and adds them to fDriveView. Sets the fHasInstallableItems member to indicate if there are any possible install targets. Automatically selects the boot drive. */ void DrivesPage::_FillDrivesView(const BootMenuList& menus) { const char* selected = fSettings->FindString("disk"); BDiskDeviceRoster roster; BDiskDevice device; while (roster.GetNextDevice(&device) == B_OK) { if (device.HasMedia() && !device.IsReadOnly()) { DriveItem* item = new DriveItem(device, menus); if (item->CanBeInstalled()) fHasInstallableItems = true; fDrivesView->AddItem(item); if ((selected == NULL && item->IsBootDrive()) || (selected != NULL && !strcmp(item->Path(), selected))) { fDrivesView->Select(fDrivesView->CountItems() - 1); _UpdateWizardButtons(item); } } } }
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 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 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); }
void AutoMounter::_UnmountAndEjectVolume(BPartition* partition, BPath& mountPoint, const char* name) { BDiskDevice deviceStorage; BDiskDevice* device; if (partition == NULL) { // Try to retrieve partition BDiskDeviceRoster().FindPartitionByMountPoint(mountPoint.Path(), &deviceStorage, &partition); device = &deviceStorage; } else { device = partition->Device(); } status_t status; if (partition != NULL) status = partition->Unmount(); else status = fs_unmount_volume(mountPoint.Path(), 0); if (status != B_OK) { if (!_SuggestForceUnmount(name, status)) return; if (partition != NULL) status = partition->Unmount(B_FORCE_UNMOUNT); else status = fs_unmount_volume(mountPoint.Path(), B_FORCE_UNMOUNT); } if (status != B_OK) { _ReportUnmountError(name, status); return; } if (fEjectWhenUnmounting && partition != NULL) { // eject device if it doesn't have any mounted partitions left class IsMountedVisitor : public BDiskDeviceVisitor { public: IsMountedVisitor() : fHasMounted(false) { } virtual bool Visit(BDiskDevice* device) { return Visit(device, 0); } virtual bool Visit(BPartition* partition, int32 level) { if (partition->IsMounted()) { fHasMounted = true; return true; } return false; } bool HasMountedPartitions() const { return fHasMounted; } private: bool fHasMounted; } visitor; device->VisitEachDescendant(&visitor); if (!visitor.HasMountedPartitions()) device->Eject(); } // remove the directory if it's a directory in rootfs if (dev_for_path(mountPoint.Path()) == dev_for_path("/")) rmdir(mountPoint.Path()); }
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; }