* 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
This commit is contained in:
@@ -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 -
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <SymLink.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 \'" <<dstItem->Name() << '\'';
|
||||
fMakeBootableButton->SetEnabled(dstItem);
|
||||
fMakeBootableButton->SetLabel(label.String());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user