Installer: CopyEngine: Externalize decision making
* Add interface EntryFilter, an instance of which can be passed to the CopyEngine. The object is asked whether to copy entries/clobber directories. * Move the _ShouldCopyEntry()/_ShouldClobberFolder() code to new WorkerThread::EntryFilter.
This commit is contained in:
@@ -19,7 +19,6 @@
|
|||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <SymLink.h>
|
#include <SymLink.h>
|
||||||
|
|
||||||
#include "InstallerDefs.h"
|
|
||||||
#include "SemaphoreLocker.h"
|
#include "SemaphoreLocker.h"
|
||||||
#include "ProgressReporter.h"
|
#include "ProgressReporter.h"
|
||||||
|
|
||||||
@@ -27,7 +26,18 @@
|
|||||||
using std::nothrow;
|
using std::nothrow;
|
||||||
|
|
||||||
|
|
||||||
CopyEngine::CopyEngine(ProgressReporter* reporter)
|
// #pragma mark - EntryFilter
|
||||||
|
|
||||||
|
|
||||||
|
CopyEngine::EntryFilter::~EntryFilter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - CopyEngine
|
||||||
|
|
||||||
|
|
||||||
|
CopyEngine::CopyEngine(ProgressReporter* reporter, EntryFilter* entryFilter)
|
||||||
:
|
:
|
||||||
fBufferQueue(),
|
fBufferQueue(),
|
||||||
fWriterThread(-1),
|
fWriterThread(-1),
|
||||||
@@ -48,7 +58,8 @@ CopyEngine::CopyEngine(ProgressReporter* reporter)
|
|||||||
fCurrentTargetFolder(NULL),
|
fCurrentTargetFolder(NULL),
|
||||||
fCurrentItem(NULL),
|
fCurrentItem(NULL),
|
||||||
|
|
||||||
fProgressReporter(reporter)
|
fProgressReporter(reporter),
|
||||||
|
fEntryFilter(entryFilter)
|
||||||
{
|
{
|
||||||
fWriterThread = spawn_thread(_WriteThreadEntry, "buffer writer",
|
fWriterThread = spawn_thread(_WriteThreadEntry, "buffer writer",
|
||||||
B_NORMAL_PRIORITY, this);
|
B_NORMAL_PRIORITY, this);
|
||||||
@@ -97,19 +108,6 @@ CopyEngine::ResetTargets(const char* source)
|
|||||||
|
|
||||||
fCurrentTargetFolder = NULL;
|
fCurrentTargetFolder = NULL;
|
||||||
fCurrentItem = NULL;
|
fCurrentItem = NULL;
|
||||||
|
|
||||||
// init BEntry pointing to /var
|
|
||||||
// There is no other way to retrieve the path to the var folder
|
|
||||||
// on the source volume. Using find_directory() with
|
|
||||||
// B_COMMON_VAR_DIRECTORY will only ever get the var folder on the
|
|
||||||
// current /boot volume regardless of the volume of "source", which
|
|
||||||
// makes sense, since passing a volume is meant to folders that are
|
|
||||||
// volume specific, like "trash".
|
|
||||||
BPath path(source);
|
|
||||||
if (path.Append(kSwapFilePath) == B_OK)
|
|
||||||
fSwapFileEntry.SetTo(path.Path());
|
|
||||||
else
|
|
||||||
fSwapFileEntry.Unset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -244,8 +242,10 @@ CopyEngine::_CollectCopyInfo(const char* _source, int32& level,
|
|||||||
if (ret < B_OK)
|
if (ret < B_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!_ShouldCopyEntry(entry, name, statInfo, level))
|
if (fEntryFilter != NULL
|
||||||
|
&& !fEntryFilter->ShouldCopyEntry(entry, name, statInfo, level)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (S_ISDIR(statInfo.st_mode)) {
|
if (S_ISDIR(statInfo.st_mode)) {
|
||||||
// handle recursive directory copy
|
// handle recursive directory copy
|
||||||
@@ -315,8 +315,10 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
|
|||||||
struct stat statInfo;
|
struct stat statInfo;
|
||||||
entry.GetStat(&statInfo);
|
entry.GetStat(&statInfo);
|
||||||
|
|
||||||
if (!_ShouldCopyEntry(entry, name, statInfo, level))
|
if (fEntryFilter != NULL
|
||||||
|
&& !fEntryFilter->ShouldCopyEntry(entry, name, statInfo, level)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
fItemsCopied++;
|
fItemsCopied++;
|
||||||
fCurrentItem = name;
|
fCurrentItem = name;
|
||||||
@@ -331,9 +333,11 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
|
|||||||
if (copy.Exists()) {
|
if (copy.Exists()) {
|
||||||
ret = B_OK;
|
ret = B_OK;
|
||||||
if (copy.IsDirectory()) {
|
if (copy.IsDirectory()) {
|
||||||
if (_ShouldClobberFolder(name, statInfo, level))
|
if (fEntryFilter
|
||||||
|
&& fEntryFilter->ShouldClobberFolder(entry, name,
|
||||||
|
statInfo, level)) {
|
||||||
ret = _RemoveFolder(copy);
|
ret = _RemoveFolder(copy);
|
||||||
else {
|
} else {
|
||||||
// Do not overwrite attributes on folders that exist.
|
// Do not overwrite attributes on folders that exist.
|
||||||
// This should work better when the install target
|
// This should work better when the install target
|
||||||
// already contains a Haiku installation.
|
// already contains a Haiku installation.
|
||||||
@@ -502,57 +506,6 @@ CopyEngine::_UpdateProgress()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CopyEngine::_ShouldCopyEntry(const BEntry& entry, const char* name,
|
|
||||||
const struct stat& statInfo, int32 level) const
|
|
||||||
{
|
|
||||||
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
|
||||||
if (strcmp(kPackagesDirectoryPath, name) == 0) {
|
|
||||||
printf("ignoring '%s'.\n", name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (strcmp(kSourcesDirectoryPath, name) == 0) {
|
|
||||||
printf("ignoring '%s'.\n", name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (strcmp("rr_moved", name) == 0) {
|
|
||||||
printf("ignoring '%s'.\n", name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (level == 1 && S_ISREG(statInfo.st_mode)) {
|
|
||||||
if (strcmp("boot.catalog", name) == 0) {
|
|
||||||
printf("ignoring '%s'.\n", name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (strcmp("haiku-boot-floppy.image", name) == 0) {
|
|
||||||
printf("ignoring '%s'.\n", name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fSwapFileEntry == entry) {
|
|
||||||
// current location of var
|
|
||||||
printf("ignoring swap file\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
CopyEngine::_ShouldClobberFolder(const char* name, const struct stat& statInfo,
|
|
||||||
int32 level) const
|
|
||||||
{
|
|
||||||
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
|
||||||
if (strcmp("system", name) == 0) {
|
|
||||||
printf("clobbering '%s'.\n", name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
CopyEngine::_WriteThreadEntry(void* cookie)
|
CopyEngine::_WriteThreadEntry(void* cookie)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,11 @@ class ProgressReporter;
|
|||||||
|
|
||||||
class CopyEngine {
|
class CopyEngine {
|
||||||
public:
|
public:
|
||||||
CopyEngine(ProgressReporter* reporter);
|
class EntryFilter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CopyEngine(ProgressReporter* reporter,
|
||||||
|
EntryFilter* entryFilter);
|
||||||
virtual ~CopyEngine();
|
virtual ~CopyEngine();
|
||||||
|
|
||||||
void ResetTargets(const char* source);
|
void ResetTargets(const char* source);
|
||||||
@@ -42,15 +46,6 @@ private:
|
|||||||
const char* destination,
|
const char* destination,
|
||||||
int32& level, sem_id cancelSemaphore);
|
int32& level, sem_id cancelSemaphore);
|
||||||
|
|
||||||
bool _ShouldCopyEntry(const BEntry& entry,
|
|
||||||
const char* name,
|
|
||||||
const struct stat& statInfo,
|
|
||||||
int32 level) const;
|
|
||||||
|
|
||||||
bool _ShouldClobberFolder(const char* name,
|
|
||||||
const struct stat& statInfo,
|
|
||||||
int32 level) const;
|
|
||||||
|
|
||||||
status_t _RemoveFolder(BEntry& entry);
|
status_t _RemoveFolder(BEntry& entry);
|
||||||
|
|
||||||
void _UpdateProgress();
|
void _UpdateProgress();
|
||||||
@@ -107,10 +102,22 @@ private:
|
|||||||
const char* fCurrentItem;
|
const char* fCurrentItem;
|
||||||
|
|
||||||
ProgressReporter* fProgressReporter;
|
ProgressReporter* fProgressReporter;
|
||||||
|
EntryFilter* fEntryFilter;
|
||||||
|
};
|
||||||
|
|
||||||
// TODO: Should be made into a list of BEntris to be ignored, perhaps.
|
|
||||||
// settable by method...
|
class CopyEngine::EntryFilter {
|
||||||
BEntry fSwapFileEntry;
|
public:
|
||||||
|
virtual ~EntryFilter();
|
||||||
|
|
||||||
|
virtual bool ShouldCopyEntry(const BEntry& entry,
|
||||||
|
const char* name,
|
||||||
|
const struct stat& statInfo,
|
||||||
|
int32 level) const = 0;
|
||||||
|
virtual bool ShouldClobberFolder(const BEntry& entry,
|
||||||
|
const char* name,
|
||||||
|
const struct stat& statInfo,
|
||||||
|
int32 level) const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,81 @@ private:
|
|||||||
// #pragma mark - WorkerThread
|
// #pragma mark - WorkerThread
|
||||||
|
|
||||||
|
|
||||||
|
class WorkerThread::EntryFilter : public CopyEngine::EntryFilter {
|
||||||
|
public:
|
||||||
|
EntryFilter(const char* sourceDirectory)
|
||||||
|
{
|
||||||
|
// init BEntry pointing to /var
|
||||||
|
// There is no other way to retrieve the path to the var folder
|
||||||
|
// on the source volume. Using find_directory() with
|
||||||
|
// B_COMMON_VAR_DIRECTORY will only ever get the var folder on the
|
||||||
|
// current /boot volume regardless of the volume of "source", which
|
||||||
|
// makes sense, since passing a volume is meant to folders that are
|
||||||
|
// volume specific, like "trash".
|
||||||
|
BPath path(sourceDirectory);
|
||||||
|
if (path.Append(kSwapFilePath) == B_OK)
|
||||||
|
fSwapFileEntry.SetTo(path.Path());
|
||||||
|
else
|
||||||
|
fSwapFileEntry.Unset();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool ShouldCopyEntry(const BEntry& entry, const char* name,
|
||||||
|
const struct stat& statInfo, int32 level) const
|
||||||
|
{
|
||||||
|
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
||||||
|
if (strcmp(kPackagesDirectoryPath, name) == 0) {
|
||||||
|
printf("ignoring '%s'.\n", name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (strcmp(kSourcesDirectoryPath, name) == 0) {
|
||||||
|
printf("ignoring '%s'.\n", name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (strcmp("rr_moved", name) == 0) {
|
||||||
|
printf("ignoring '%s'.\n", name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (level == 1 && S_ISREG(statInfo.st_mode)) {
|
||||||
|
if (strcmp("boot.catalog", name) == 0) {
|
||||||
|
printf("ignoring '%s'.\n", name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (strcmp("haiku-boot-floppy.image", name) == 0) {
|
||||||
|
printf("ignoring '%s'.\n", name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fSwapFileEntry == entry) {
|
||||||
|
// current location of var
|
||||||
|
printf("ignoring swap file\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool ShouldClobberFolder(const BEntry& entry, const char* name,
|
||||||
|
const struct stat& statInfo, int32 level) const
|
||||||
|
{
|
||||||
|
if (level == 1 && S_ISDIR(statInfo.st_mode)) {
|
||||||
|
if (strcmp("system", name) == 0) {
|
||||||
|
printf("clobbering '%s'.\n", name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TODO: Should be made into a list of BEntris to be ignored, perhaps.
|
||||||
|
// settable by method...
|
||||||
|
BEntry fSwapFileEntry;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - WorkerThread
|
||||||
|
|
||||||
|
|
||||||
WorkerThread::WorkerThread(InstallerWindow *window)
|
WorkerThread::WorkerThread(InstallerWindow *window)
|
||||||
:
|
:
|
||||||
BLooper("copy_engine"),
|
BLooper("copy_engine"),
|
||||||
@@ -266,11 +341,6 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
|
|||||||
const char* mountError = B_TRANSLATE("The disk can't be mounted. Please "
|
const char* mountError = B_TRANSLATE("The disk can't be mounted. Please "
|
||||||
"choose a different disk.");
|
"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* targetItem = (PartitionMenuItem*)targetMenu->FindMarked();
|
||||||
PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked();
|
PartitionMenuItem* srcItem = (PartitionMenuItem*)srcMenu->FindMarked();
|
||||||
if (!srcItem || !targetItem) {
|
if (!srcItem || !targetItem) {
|
||||||
@@ -401,6 +471,13 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
|
|||||||
|
|
||||||
// Begin actual installation
|
// Begin actual installation
|
||||||
|
|
||||||
|
{
|
||||||
|
BMessenger messenger(fWindow);
|
||||||
|
ProgressReporter reporter(messenger, new BMessage(MSG_STATUS_MESSAGE));
|
||||||
|
EntryFilter entryFilter(srcDirectory.Path());
|
||||||
|
CopyEngine engine(&reporter, &entryFilter);
|
||||||
|
BList unzipEngines;
|
||||||
|
|
||||||
_LaunchInitScript(targetDirectory);
|
_LaunchInitScript(targetDirectory);
|
||||||
|
|
||||||
// Create the default indices which should always be present on a proper
|
// Create the default indices which should always be present on a proper
|
||||||
@@ -480,6 +557,8 @@ WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
|
|||||||
BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);
|
BMessenger(fWindow).SendMessage(MSG_INSTALL_FINISHED);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
BMessage statusMessage(MSG_RESET);
|
BMessage statusMessage(MSG_RESET);
|
||||||
if (err == B_CANCELED)
|
if (err == B_CANCELED)
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ private:
|
|||||||
|
|
||||||
void _SetStatusMessage(const char* status);
|
void _SetStatusMessage(const char* status);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class EntryFilter;
|
||||||
|
|
||||||
|
private:
|
||||||
InstallerWindow* fWindow;
|
InstallerWindow* fWindow;
|
||||||
BDiskDeviceRoster fDDRoster;
|
BDiskDeviceRoster fDDRoster;
|
||||||
BList* fPackages;
|
BList* fPackages;
|
||||||
|
|||||||
Reference in New Issue
Block a user