* 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
|
void
|
||||||
CopyEngine::MessageReceived(BMessage*msg)
|
CopyEngine::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
switch (msg->what) {
|
|
||||||
|
switch (message->what) {
|
||||||
case ENGINE_START:
|
case ENGINE_START:
|
||||||
{
|
|
||||||
Start(fWindow->GetSourceMenu(), fWindow->GetTargetMenu());
|
Start(fWindow->GetSourceMenu(), fWindow->GetTargetMenu());
|
||||||
break;
|
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 -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ class CopyEngine : public BLooper {
|
|||||||
void SetSpaceRequired(off_t bytes) { fSpaceRequired = bytes; };
|
void SetSpaceRequired(off_t bytes) { fSpaceRequired = bytes; };
|
||||||
bool Cancel();
|
bool Cancel();
|
||||||
void SetLock(BLocker* lock) { fCancelLock = lock; }
|
void SetLock(BLocker* lock) { fCancelLock = lock; }
|
||||||
|
void WriteBootSector(BMenu *targetMenu);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void LaunchInitScript(BPath &path);
|
void LaunchInitScript(BPath &path);
|
||||||
void LaunchFinishScript(BPath &path);
|
void LaunchFinishScript(BPath &path);
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
#include <SymLink.h>
|
#include <SymLink.h>
|
||||||
|
|
||||||
#include "AutoLocker.h"
|
#include "AutoLocker.h"
|
||||||
|
#include "InstallerWindow.h"
|
||||||
|
// TODO: For PACKAGES_DIRECTORY and VAR_DIRECTORY, not so nice...
|
||||||
|
|
||||||
using std::nothrow;
|
using std::nothrow;
|
||||||
|
|
||||||
@@ -80,7 +82,8 @@ CopyEngine2::CopyFolder(const char* source, const char* destination,
|
|||||||
fCurrentTargetFolder = NULL;
|
fCurrentTargetFolder = NULL;
|
||||||
fCurrentItem = NULL;
|
fCurrentItem = NULL;
|
||||||
|
|
||||||
status_t ret = _CollectCopyInfo(source);
|
int32 level = 0;
|
||||||
|
status_t ret = _CollectCopyInfo(source, level);
|
||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
return ret;
|
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);
|
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
|
status_t
|
||||||
CopyEngine2::_CollectCopyInfo(const char* _source)
|
CopyEngine2::_CollectCopyInfo(const char* _source, int32& level)
|
||||||
{
|
{
|
||||||
|
level++;
|
||||||
|
|
||||||
BDirectory source(_source);
|
BDirectory source(_source);
|
||||||
status_t ret = source.InitCheck();
|
status_t ret = source.InitCheck();
|
||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
@@ -192,6 +198,14 @@ CopyEngine2::_CollectCopyInfo(const char* _source)
|
|||||||
struct stat statInfo;
|
struct stat statInfo;
|
||||||
entry.GetStat(&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)) {
|
if (S_ISDIR(statInfo.st_mode)) {
|
||||||
// handle recursive directory copy
|
// handle recursive directory copy
|
||||||
BPath srcFolder;
|
BPath srcFolder;
|
||||||
@@ -199,31 +213,29 @@ CopyEngine2::_CollectCopyInfo(const char* _source)
|
|||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = _CollectCopyInfo(srcFolder.Path());
|
ret = _CollectCopyInfo(srcFolder.Path(), level);
|
||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
return ret;
|
return ret;
|
||||||
} else if (S_ISLNK(statInfo.st_mode)) {
|
} else if (S_ISLNK(statInfo.st_mode)) {
|
||||||
|
// link, ignore size
|
||||||
} else {
|
} else {
|
||||||
// file data
|
// file data
|
||||||
off_t size;
|
fBytesToCopy += statInfo.st_size;
|
||||||
ret = entry.GetSize(&size);
|
|
||||||
if (ret < B_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
fBytesToCopy += size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fItemsToCopy++;
|
fItemsToCopy++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level--;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
CopyEngine2::_CopyFolder(const char* _source, const char* _destination,
|
CopyEngine2::_CopyFolder(const char* _source, const char* _destination,
|
||||||
BLocker* locker)
|
int32& level, BLocker* locker)
|
||||||
{
|
{
|
||||||
|
level++;
|
||||||
fCurrentTargetFolder = _destination;
|
fCurrentTargetFolder = _destination;
|
||||||
|
|
||||||
BDirectory source(_source);
|
BDirectory source(_source);
|
||||||
@@ -253,18 +265,29 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination,
|
|||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
fItemsCopied++;
|
|
||||||
fCurrentItem = name;
|
|
||||||
|
|
||||||
_UpdateProgress();
|
|
||||||
|
|
||||||
struct stat statInfo;
|
struct stat statInfo;
|
||||||
entry.GetStat(&statInfo);
|
entry.GetStat(&statInfo);
|
||||||
|
|
||||||
|
if (!_ShouldCopyEntry(name, statInfo, level))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
fItemsCopied++;
|
||||||
|
fCurrentItem = name;
|
||||||
|
_UpdateProgress();
|
||||||
|
|
||||||
BEntry copy(&destination, name);
|
BEntry copy(&destination, name);
|
||||||
|
bool copyAttributes = true;
|
||||||
|
|
||||||
if (S_ISDIR(statInfo.st_mode)) {
|
if (S_ISDIR(statInfo.st_mode)) {
|
||||||
// handle recursive directory copy
|
// 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;
|
BPath srcFolder;
|
||||||
ret = entry.GetPath(&srcFolder);
|
ret = entry.GetPath(&srcFolder);
|
||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
@@ -278,7 +301,8 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination,
|
|||||||
if (locker != NULL)
|
if (locker != NULL)
|
||||||
lock.Unlock();
|
lock.Unlock();
|
||||||
|
|
||||||
ret = _CopyFolder(srcFolder.Path(), dstFolder.Path(), locker);
|
ret = _CopyFolder(srcFolder.Path(), dstFolder.Path(), level,
|
||||||
|
locker);
|
||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -312,6 +336,9 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!copyAttributes)
|
||||||
|
continue;
|
||||||
|
|
||||||
// copy attributes
|
// copy attributes
|
||||||
BNode sourceNode(&entry);
|
BNode sourceNode(&entry);
|
||||||
BNode targetNode(©);
|
BNode targetNode(©);
|
||||||
@@ -325,6 +352,8 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination,
|
|||||||
off_t offset = 0;
|
off_t offset = 0;
|
||||||
ssize_t read = sourceNode.ReadAttr(attrName, info.type,
|
ssize_t read = sourceNode.ReadAttr(attrName, info.type,
|
||||||
offset, buffer, min_c(size, info.size));
|
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) {
|
while (read >= 0) {
|
||||||
targetNode.WriteAttr(attrName, info.type, offset, buffer, read);
|
targetNode.WriteAttr(attrName, info.type, offset, buffer, read);
|
||||||
offset += read;
|
offset += read;
|
||||||
@@ -343,6 +372,7 @@ CopyEngine2::_CopyFolder(const char* _source, const char* _destination,
|
|||||||
copy.SetCreationTime(statInfo.st_crtime);
|
copy.SetCreationTime(statInfo.st_crtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level--;
|
||||||
return B_OK;
|
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
|
int32
|
||||||
CopyEngine2::_WriteThreadEntry(void* cookie)
|
CopyEngine2::_WriteThreadEntry(void* cookie)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -28,11 +28,17 @@ public:
|
|||||||
BLocker* locker = NULL);
|
BLocker* locker = NULL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _CollectCopyInfo(const char* source);
|
status_t _CollectCopyInfo(const char* source,
|
||||||
|
int32& level);
|
||||||
status_t _CopyFolder(const char* source,
|
status_t _CopyFolder(const char* source,
|
||||||
const char* destination,
|
const char* destination,
|
||||||
|
int32& level,
|
||||||
BLocker* locker = NULL);
|
BLocker* locker = NULL);
|
||||||
|
|
||||||
|
bool _ShouldCopyEntry(const char* name,
|
||||||
|
const struct stat& statInfo,
|
||||||
|
int32 level) const;
|
||||||
|
|
||||||
void _UpdateProgress();
|
void _UpdateProgress();
|
||||||
|
|
||||||
static int32 _WriteThreadEntry(void* cookie);
|
static int32 _WriteThreadEntry(void* cookie);
|
||||||
|
|||||||
@@ -264,6 +264,10 @@ InstallerWindow::InstallerWindow()
|
|||||||
fSetupButton = new BButton("setup_button",
|
fSetupButton = new BButton("setup_button",
|
||||||
"Setup partitions" B_UTF8_ELLIPSIS, new BMessage(SETUP_MESSAGE));
|
"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));
|
SetLayout(new BGroupLayout(B_HORIZONTAL));
|
||||||
AddChild(BGroupLayoutBuilder(B_VERTICAL)
|
AddChild(BGroupLayoutBuilder(B_VERTICAL)
|
||||||
.Add(BGroupLayoutBuilder(B_HORIZONTAL)
|
.Add(BGroupLayoutBuilder(B_HORIZONTAL)
|
||||||
@@ -286,8 +290,9 @@ InstallerWindow::InstallerWindow()
|
|||||||
.Add(fSizeView, 0, 6, 2)
|
.Add(fSizeView, 0, 6, 2)
|
||||||
)
|
)
|
||||||
|
|
||||||
.Add(BGroupLayoutBuilder(B_HORIZONTAL)
|
.Add(BGroupLayoutBuilder(B_HORIZONTAL, 10)
|
||||||
.Add(fSetupButton)
|
.Add(fSetupButton)
|
||||||
|
.Add(fMakeBootableButton)
|
||||||
.AddGlue()
|
.AddGlue()
|
||||||
.Add(fBeginButton)
|
.Add(fBeginButton)
|
||||||
)
|
)
|
||||||
@@ -437,8 +442,10 @@ InstallerWindow::MessageReceived(BMessage *msg)
|
|||||||
}
|
}
|
||||||
case STATUS_MESSAGE:
|
case STATUS_MESSAGE:
|
||||||
{
|
{
|
||||||
if (fInstallStatus != kInstalling)
|
// TODO: Was this supposed to prevent status messages still arriving
|
||||||
break;
|
// after the copy engine was shut down?
|
||||||
|
// if (fInstallStatus != kInstalling)
|
||||||
|
// break;
|
||||||
float progress;
|
float progress;
|
||||||
if (msg->FindFloat("progress", &progress) == B_OK) {
|
if (msg->FindFloat("progress", &progress) == B_OK) {
|
||||||
const char* currentItem;
|
const char* currentItem;
|
||||||
@@ -466,17 +473,27 @@ InstallerWindow::MessageReceived(BMessage *msg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case INSTALL_FINISHED:
|
case INSTALL_FINISHED:
|
||||||
|
{
|
||||||
delete fCopyEngineLock;
|
delete fCopyEngineLock;
|
||||||
fCopyEngineLock = NULL;
|
fCopyEngineLock = NULL;
|
||||||
|
|
||||||
fBeginButton->SetLabel("Quit");
|
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;
|
fInstallStatus = kFinished;
|
||||||
_DisableInterface(false);
|
_DisableInterface(false);
|
||||||
fProgressLayoutItem->SetVisible(false);
|
fProgressLayoutItem->SetVisible(false);
|
||||||
fPkgSwitchLayoutItem->SetVisible(true);
|
fPkgSwitchLayoutItem->SetVisible(true);
|
||||||
_ShowOptionalPackages();
|
_ShowOptionalPackages();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case B_SOME_APP_LAUNCHED:
|
case B_SOME_APP_LAUNCHED:
|
||||||
case B_SOME_APP_QUIT:
|
case B_SOME_APP_QUIT:
|
||||||
{
|
{
|
||||||
@@ -495,6 +512,10 @@ InstallerWindow::MessageReceived(BMessage *msg)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kWriteBootSector:
|
||||||
|
fCopyEngine->WriteBootSector(fDestMenu);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BWindow::MessageReceived(msg);
|
BWindow::MessageReceived(msg);
|
||||||
break;
|
break;
|
||||||
@@ -643,6 +664,13 @@ InstallerWindow::_UpdateControls()
|
|||||||
fInstallStatus = kReadyForInstall;
|
fInstallStatus = kReadyForInstall;
|
||||||
fBeginButton->SetLabel("Begin");
|
fBeginButton->SetLabel("Begin");
|
||||||
fBeginButton->SetEnabled(srcItem && dstItem);
|
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 STATUS_MESSAGE = 'iSTM';
|
||||||
const uint32 INSTALL_FINISHED = 'iIFN';
|
const uint32 INSTALL_FINISHED = 'iIFN';
|
||||||
const uint32 RESET_INSTALL = 'iRSI';
|
const uint32 RESET_INSTALL = 'iRSI';
|
||||||
|
const uint32 kWriteBootSector = 'iWBS';
|
||||||
|
|
||||||
const char PACKAGES_DIRECTORY[] = "_packages_";
|
const char PACKAGES_DIRECTORY[] = "_packages_";
|
||||||
const char VAR_DIRECTORY[] = "var";
|
const char VAR_DIRECTORY[] = "var";
|
||||||
|
|
||||||
@@ -83,6 +85,7 @@ private:
|
|||||||
|
|
||||||
BButton* fBeginButton;
|
BButton* fBeginButton;
|
||||||
BButton* fSetupButton;
|
BButton* fSetupButton;
|
||||||
|
BButton* fMakeBootableButton;
|
||||||
|
|
||||||
bool fNeedsToCenterOnScreen;
|
bool fNeedsToCenterOnScreen;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user