From 7b293a3e9352708b1d067a4f4cd4c7a19ab7e64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sat, 25 Apr 2009 15:35:49 +0000 Subject: [PATCH] * Prevent to copy the "var" and "_packages_" folders from the source volume root folder as before switching the CopyEngine. * Add a button "Write Boot Sector" that makes the selected target volume bootable without performing an installation. Adjusted the status message after installation to be more descriptive. * Small improvements in the CopyEngine, collecting the source size should be even a bit faster now since we can use the file size from the already performed stat(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30395 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/installer/CopyEngine.cpp | 70 +++++++++++++++++++++- src/apps/installer/CopyEngine.h | 2 + src/apps/installer/CopyEngine2.cpp | 82 ++++++++++++++++++++------ src/apps/installer/CopyEngine2.h | 8 ++- src/apps/installer/InstallerWindow.cpp | 36 +++++++++-- src/apps/installer/InstallerWindow.h | 3 + 6 files changed, 176 insertions(+), 25 deletions(-) diff --git a/src/apps/installer/CopyEngine.cpp b/src/apps/installer/CopyEngine.cpp index 08a9d330da..d737d2135c 100644 --- a/src/apps/installer/CopyEngine.cpp +++ b/src/apps/installer/CopyEngine.cpp @@ -75,15 +75,61 @@ CopyEngine::CopyEngine(InstallerWindow *window) void -CopyEngine::MessageReceived(BMessage*msg) +CopyEngine::MessageReceived(BMessage* message) { CALLED(); - switch (msg->what) { + + switch (message->what) { case ENGINE_START: - { Start(fWindow->GetSourceMenu(), fWindow->GetTargetMenu()); break; + + case kWriteBootSector: + { + int32 id; + if (message->FindInt32("id", &id) != B_OK) { + SetStatusMessage("Boot sector not written because of an " + " internal error."); + break; + } + + // TODO: Refactor with Start() + BPath targetDirectory; + BDiskDevice device; + BPartition* partition; + + if (fDDRoster.GetPartitionWithID(id, &device, &partition) == B_OK) { + if (!partition->IsMounted()) { + if (partition->Mount() < B_OK) { + SetStatusMessage("The partition can't be mounted. " + "Please choose a different partition."); + break; + } + } + if (partition->GetMountPoint(&targetDirectory) != B_OK) { + SetStatusMessage("The mount point could not be retrieve."); + break; + } + } else if (fDDRoster.GetDeviceWithID(id, &device) == B_OK) { + if (!device.IsMounted()) { + if (device.Mount() < B_OK) { + SetStatusMessage("The disk can't be mounted. Please " + "choose a different disk."); + break; + } + } + if (device.GetMountPoint(&targetDirectory) != B_OK) { + SetStatusMessage("The mount point could not be retrieve."); + break; + } + } + + LaunchFinishScript(targetDirectory); + // TODO: Get error from executing script! + SetStatusMessage("Boot sector successfully written."); } + default: + BLooper::MessageReceived(message); } } @@ -398,6 +444,24 @@ CopyEngine::Cancel() } +void +CopyEngine::WriteBootSector(BMenu* targetMenu) +{ + // Executed in window thread. + CALLED(); + + PartitionMenuItem* item = (PartitionMenuItem*)targetMenu->FindMarked(); + if (item == NULL) { + ERR("bad menu items\n"); + return; + } + + BMessage message(kWriteBootSector); + message.AddInt32("id", item->ID()); + PostMessage(&message, this); +} + + // #pragma mark - diff --git a/src/apps/installer/CopyEngine.h b/src/apps/installer/CopyEngine.h index 2e725489f7..8de3ccc342 100644 --- a/src/apps/installer/CopyEngine.h +++ b/src/apps/installer/CopyEngine.h @@ -29,6 +29,8 @@ class CopyEngine : public BLooper { void SetSpaceRequired(off_t bytes) { fSpaceRequired = bytes; }; bool Cancel(); void SetLock(BLocker* lock) { fCancelLock = lock; } + void WriteBootSector(BMenu *targetMenu); + private: void LaunchInitScript(BPath &path); void LaunchFinishScript(BPath &path); diff --git a/src/apps/installer/CopyEngine2.cpp b/src/apps/installer/CopyEngine2.cpp index 081976c0f1..a616ad1a42 100644 --- a/src/apps/installer/CopyEngine2.cpp +++ b/src/apps/installer/CopyEngine2.cpp @@ -14,6 +14,8 @@ #include #include "AutoLocker.h" +#include "InstallerWindow.h" + // TODO: For PACKAGES_DIRECTORY and VAR_DIRECTORY, not so nice... using std::nothrow; @@ -80,7 +82,8 @@ CopyEngine2::CopyFolder(const char* source, const char* destination, fCurrentTargetFolder = NULL; fCurrentItem = NULL; - status_t ret = _CollectCopyInfo(source); + int32 level = 0; + status_t ret = _CollectCopyInfo(source, level); if (ret < B_OK) return ret; @@ -92,7 +95,8 @@ CopyEngine2::CopyFolder(const char* source, const char* destination, printf("%lld bytes to read in %lld files\n", fBytesToCopy, fItemsToCopy); - return _CopyFolder(source, destination, locker); + level = 0; + return _CopyFolder(source, destination, level, locker); } @@ -180,8 +184,10 @@ printf("CopyFile - cancled\n"); status_t -CopyEngine2::_CollectCopyInfo(const char* _source) +CopyEngine2::_CollectCopyInfo(const char* _source, int32& level) { + level++; + BDirectory source(_source); status_t ret = source.InitCheck(); if (ret < B_OK) @@ -192,6 +198,14 @@ CopyEngine2::_CollectCopyInfo(const char* _source) struct stat statInfo; entry.GetStat(&statInfo); + char name[B_FILE_NAME_LENGTH]; + status_t ret = entry.GetName(name); + if (ret < B_OK) + return ret; + + if (!_ShouldCopyEntry(name, statInfo, level)) + continue; + if (S_ISDIR(statInfo.st_mode)) { // handle recursive directory copy BPath srcFolder; @@ -199,31 +213,29 @@ CopyEngine2::_CollectCopyInfo(const char* _source) if (ret < B_OK) return ret; - ret = _CollectCopyInfo(srcFolder.Path()); + ret = _CollectCopyInfo(srcFolder.Path(), level); if (ret < B_OK) return ret; } else if (S_ISLNK(statInfo.st_mode)) { + // link, ignore size } else { // file data - off_t size; - ret = entry.GetSize(&size); - if (ret < B_OK) - return ret; - - fBytesToCopy += size; + fBytesToCopy += statInfo.st_size; } fItemsToCopy++; } + level--; return B_OK; } status_t CopyEngine2::_CopyFolder(const char* _source, const char* _destination, - BLocker* locker) + int32& level, BLocker* locker) { + level++; fCurrentTargetFolder = _destination; BDirectory source(_source); @@ -253,18 +265,29 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination, if (ret < B_OK) return ret; - fItemsCopied++; - fCurrentItem = name; - - _UpdateProgress(); - struct stat statInfo; entry.GetStat(&statInfo); + if (!_ShouldCopyEntry(name, statInfo, level)) + continue; + + fItemsCopied++; + fCurrentItem = name; + _UpdateProgress(); + BEntry copy(&destination, name); + bool copyAttributes = true; if (S_ISDIR(statInfo.st_mode)) { // handle recursive directory copy + + if (copy.Exists()) { + // Do not overwrite attributes on folders that exist. + // This should work better when the install target already + // contains a Haiku installation. + copyAttributes = false; + } + BPath srcFolder; ret = entry.GetPath(&srcFolder); if (ret < B_OK) @@ -278,7 +301,8 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination, if (locker != NULL) lock.Unlock(); - ret = _CopyFolder(srcFolder.Path(), dstFolder.Path(), locker); + ret = _CopyFolder(srcFolder.Path(), dstFolder.Path(), level, + locker); if (ret < B_OK) return ret; @@ -312,6 +336,9 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination, return ret; } + if (!copyAttributes) + continue; + // copy attributes BNode sourceNode(&entry); BNode targetNode(©); @@ -325,6 +352,8 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination, off_t offset = 0; ssize_t read = sourceNode.ReadAttr(attrName, info.type, offset, buffer, min_c(size, info.size)); + // NOTE: It's important to still write the attribute even if + // we have read 0 bytes! while (read >= 0) { targetNode.WriteAttr(attrName, info.type, offset, buffer, read); offset += read; @@ -343,6 +372,7 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination, copy.SetCreationTime(statInfo.st_crtime); } + level--; return B_OK; } @@ -363,6 +393,24 @@ CopyEngine2::_UpdateProgress() } +bool +CopyEngine2::_ShouldCopyEntry(const char* name, const struct stat& statInfo, + int32 level) const +{ + if (level == 1 && S_ISDIR(statInfo.st_mode)) { + if (strcmp(VAR_DIRECTORY, name) == 0) { + printf("ignoring '%s'.\n", name); + return false; + } + if (strcmp(PACKAGES_DIRECTORY, name) == 0) { + printf("ignoring '%s'.\n", name); + return false; + } + } + return true; +} + + int32 CopyEngine2::_WriteThreadEntry(void* cookie) { diff --git a/src/apps/installer/CopyEngine2.h b/src/apps/installer/CopyEngine2.h index 8c68b947bf..11578821eb 100644 --- a/src/apps/installer/CopyEngine2.h +++ b/src/apps/installer/CopyEngine2.h @@ -28,11 +28,17 @@ public: BLocker* locker = NULL); private: - status_t _CollectCopyInfo(const char* source); + status_t _CollectCopyInfo(const char* source, + int32& level); status_t _CopyFolder(const char* source, const char* destination, + int32& level, BLocker* locker = NULL); + bool _ShouldCopyEntry(const char* name, + const struct stat& statInfo, + int32 level) const; + void _UpdateProgress(); static int32 _WriteThreadEntry(void* cookie); diff --git a/src/apps/installer/InstallerWindow.cpp b/src/apps/installer/InstallerWindow.cpp index 7e998348c5..7eda7b13d4 100644 --- a/src/apps/installer/InstallerWindow.cpp +++ b/src/apps/installer/InstallerWindow.cpp @@ -264,6 +264,10 @@ InstallerWindow::InstallerWindow() fSetupButton = new BButton("setup_button", "Setup partitions" B_UTF8_ELLIPSIS, new BMessage(SETUP_MESSAGE)); + fMakeBootableButton = new BButton("makebootable_button", + "Write Boot Sector", new BMessage(kWriteBootSector)); + fMakeBootableButton->SetEnabled(false); + SetLayout(new BGroupLayout(B_HORIZONTAL)); AddChild(BGroupLayoutBuilder(B_VERTICAL) .Add(BGroupLayoutBuilder(B_HORIZONTAL) @@ -286,8 +290,9 @@ InstallerWindow::InstallerWindow() .Add(fSizeView, 0, 6, 2) ) - .Add(BGroupLayoutBuilder(B_HORIZONTAL) + .Add(BGroupLayoutBuilder(B_HORIZONTAL, 10) .Add(fSetupButton) + .Add(fMakeBootableButton) .AddGlue() .Add(fBeginButton) ) @@ -437,8 +442,10 @@ InstallerWindow::MessageReceived(BMessage *msg) } case STATUS_MESSAGE: { - if (fInstallStatus != kInstalling) - break; +// TODO: Was this supposed to prevent status messages still arriving +// after the copy engine was shut down? +// if (fInstallStatus != kInstalling) +// break; float progress; if (msg->FindFloat("progress", &progress) == B_OK) { const char* currentItem; @@ -466,17 +473,27 @@ InstallerWindow::MessageReceived(BMessage *msg) break; } case INSTALL_FINISHED: + { delete fCopyEngineLock; fCopyEngineLock = NULL; fBeginButton->SetLabel("Quit"); - _SetStatusMessage("Installation completed."); + + PartitionMenuItem* dstItem + = (PartitionMenuItem*)fDestMenu->FindMarked(); + char status[1024]; + snprintf(status, sizeof(status), "Installation completed. " + "Boot sector has been written to '%s'. Press Quit to reboot " + "or chose a new target volume to perform another " + "installation.", dstItem ? dstItem->Name() : "???"); + _SetStatusMessage(status); fInstallStatus = kFinished; _DisableInterface(false); fProgressLayoutItem->SetVisible(false); fPkgSwitchLayoutItem->SetVisible(true); _ShowOptionalPackages(); break; + } case B_SOME_APP_LAUNCHED: case B_SOME_APP_QUIT: { @@ -495,6 +512,10 @@ InstallerWindow::MessageReceived(BMessage *msg) } break; } + case kWriteBootSector: + fCopyEngine->WriteBootSector(fDestMenu); + break; + default: BWindow::MessageReceived(msg); break; @@ -643,6 +664,13 @@ InstallerWindow::_UpdateControls() fInstallStatus = kReadyForInstall; fBeginButton->SetLabel("Begin"); fBeginButton->SetEnabled(srcItem && dstItem); + + // adjust "Write Boot Sector" button + label = "Write Boot Sector"; + if (dstItem) + label << " to \'" <Name() << '\''; + fMakeBootableButton->SetEnabled(dstItem); + fMakeBootableButton->SetLabel(label.String()); } diff --git a/src/apps/installer/InstallerWindow.h b/src/apps/installer/InstallerWindow.h index 7d9b200135..95f94cbe7b 100644 --- a/src/apps/installer/InstallerWindow.h +++ b/src/apps/installer/InstallerWindow.h @@ -35,6 +35,8 @@ enum InstallStatus { const uint32 STATUS_MESSAGE = 'iSTM'; const uint32 INSTALL_FINISHED = 'iIFN'; const uint32 RESET_INSTALL = 'iRSI'; +const uint32 kWriteBootSector = 'iWBS'; + const char PACKAGES_DIRECTORY[] = "_packages_"; const char VAR_DIRECTORY[] = "var"; @@ -83,6 +85,7 @@ private: BButton* fBeginButton; BButton* fSetupButton; + BButton* fMakeBootableButton; bool fNeedsToCenterOnScreen;