* Fixed problems when installing onto non-empty target volumes. The

'system' folder will be a clean copy of the source volume. Other
  folders will be merged (as before), but in case a folder is in the
  way of a link or file from the source volume, it will now be purged.
* Clarified the alert for non-empty target volumes, so it is very clear
  what happens. (Maybe there ought to the be option to only copy the system
  folder, though.)
* Fixed a problem with copying attributes in certain cases.
* Fixed the main GUI not resetting state properly after encountering an
  error during the copy process.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31042 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2009-06-14 11:07:52 +00:00
parent f664c6474b
commit f76e944e24
4 changed files with 121 additions and 37 deletions

View File

@ -263,8 +263,11 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
return ret; return ret;
ret = create_directory(_destination, 0777); ret = create_directory(_destination, 0777);
if (ret < B_OK && ret != B_FILE_EXISTS) if (ret < B_OK && ret != B_FILE_EXISTS) {
fprintf(stderr, "Could not create '%s': %s\n", _destination,
strerror(ret));
return ret; return ret;
}
BDirectory destination(_destination); BDirectory destination(_destination);
ret = destination.InitCheck(); ret = destination.InitCheck();
@ -301,10 +304,24 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
// handle recursive directory copy // handle recursive directory copy
if (copy.Exists()) { if (copy.Exists()) {
// Do not overwrite attributes on folders that exist. ret = B_OK;
// This should work better when the install target already if (copy.IsDirectory()) {
// contains a Haiku installation. if (_ShouldClobberFolder(name, statInfo, level))
copyAttributes = false; ret = _RemoveFolder(copy);
else {
// Do not overwrite attributes on folders that exist.
// This should work better when the install target
// already contains a Haiku installation.
copyAttributes = false;
}
} else
ret = copy.Remove();
if (ret != B_OK) {
fprintf(stderr, "Failed to make room for folder '%s': "
"%s\n", name, strerror(ret));
return ret;
}
} }
BPath srcFolder; BPath srcFolder;
@ -329,35 +346,52 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
// We are supposed to quit // We are supposed to quit
return B_CANCELED; return B_CANCELED;
} }
} else if (S_ISLNK(statInfo.st_mode)) {
// copy symbolic links
BSymLink srcLink(&entry);
if (ret < B_OK)
return ret;
char linkPath[B_PATH_NAME_LENGTH];
ssize_t read = srcLink.ReadLink(linkPath, B_PATH_NAME_LENGTH - 1);
if (read < 0)
return (status_t)read;
// just in case it already exists...
copy.Remove();
BSymLink dstLink;
ret = destination.CreateSymLink(name, linkPath, &dstLink);
if (ret < B_OK)
return ret;
} else { } else {
// copy file data if (copy.Exists()) {
// NOTE: Do not pass the locker, we simply keep holding the lock! if (copy.IsDirectory())
ret = CopyFile(entry, copy); ret = _RemoveFolder(copy);
if (ret < B_OK) else
return ret; ret = copy.Remove();
if (ret != B_OK) {
fprintf(stderr, "Failed to make room for entry '%s': "
"%s\n", name, strerror(ret));
return ret;
}
}
if (S_ISLNK(statInfo.st_mode)) {
// copy symbolic links
BSymLink srcLink(&entry);
if (ret < B_OK)
return ret;
char linkPath[B_PATH_NAME_LENGTH];
ssize_t read = srcLink.ReadLink(linkPath, B_PATH_NAME_LENGTH - 1);
if (read < 0)
return (status_t)read;
// just in case it already exists...
copy.Remove();
BSymLink dstLink;
ret = destination.CreateSymLink(name, linkPath, &dstLink);
if (ret < B_OK)
return ret;
} else {
// copy file data
// NOTE: Do not pass the locker, we simply keep holding the lock!
ret = CopyFile(entry, copy);
if (ret < B_OK)
return ret;
}
} }
if (!copyAttributes) if (!copyAttributes)
continue; continue;
ret = copy.SetTo(&destination, name);
if (ret != B_OK)
return ret;
// copy attributes // copy attributes
BNode sourceNode(&entry); BNode sourceNode(&entry);
BNode targetNode(&copy); BNode targetNode(&copy);
@ -396,6 +430,30 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination,
} }
status_t
CopyEngine::_RemoveFolder(BEntry& entry)
{
BDirectory directory(&entry);
status_t ret = directory.InitCheck();
if (ret != B_OK)
return ret;
BEntry subEntry;
while (directory.GetNextEntry(&subEntry) == B_OK) {
if (subEntry.IsDirectory()) {
ret = _RemoveFolder(subEntry);
if (ret != B_OK)
return ret;
} else {
ret = subEntry.Remove();
if (ret != B_OK)
return ret;
}
}
return entry.Remove();
}
void void
CopyEngine::_UpdateProgress() CopyEngine::_UpdateProgress()
{ {
@ -430,6 +488,24 @@ CopyEngine::_ShouldCopyEntry(const char* name, const struct stat& statInfo,
} }
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;
}
// if (strcmp("develop", name) == 0) {
// printf("clobbering '%s'.\n", name);
// return true;
// }
}
return false;
}
int32 int32
CopyEngine::_WriteThreadEntry(void* cookie) CopyEngine::_WriteThreadEntry(void* cookie)
{ {

View File

@ -48,6 +48,12 @@ private:
const struct stat& statInfo, const struct stat& statInfo,
int32 level) const; int32 level) const;
bool _ShouldClobberFolder(const char* name,
const struct stat& statInfo,
int32 level) const;
status_t _RemoveFolder(BEntry& entry);
void _UpdateProgress(); void _UpdateProgress();
static int32 _WriteThreadEntry(void* cookie); static int32 _WriteThreadEntry(void* cookie);

View File

@ -373,15 +373,12 @@ InstallerWindow::MessageReceived(BMessage *msg)
(new BAlert("error", errorMessage, "Ok"))->Go(); (new BAlert("error", errorMessage, "Ok"))->Go();
} }
fInstallStatus = kReadyForInstall;
fBeginButton->SetEnabled(true);
_DisableInterface(false); _DisableInterface(false);
fProgressLayoutItem->SetVisible(false); fProgressLayoutItem->SetVisible(false);
fPkgSwitchLayoutItem->SetVisible(true); fPkgSwitchLayoutItem->SetVisible(true);
_ShowOptionalPackages(); _ShowOptionalPackages();
_UpdateControls();
fBeginButton->SetLabel("Begin");
break; break;
} }
case START_SCAN: case START_SCAN:

View File

@ -234,14 +234,14 @@ WorkerThread::_LaunchFinishScript(BPath &path)
void void
WorkerThread::_PerformInstall(BMenu *srcMenu, BMenu *targetMenu) WorkerThread::_PerformInstall(BMenu* srcMenu, BMenu* targetMenu)
{ {
CALLED(); CALLED();
BPath targetDirectory, srcDirectory; BPath targetDirectory, srcDirectory;
BDirectory targetDir; BDirectory targetDir;
BDiskDevice device; BDiskDevice device;
BPartition *partition; BPartition* partition;
BVolume targetVolume; BVolume targetVolume;
status_t err = B_OK; status_t err = B_OK;
int32 entries = 0; int32 entries = 0;
@ -250,8 +250,8 @@ WorkerThread::_PerformInstall(BMenu *srcMenu, BMenu *targetMenu)
BMessenger messenger(fWindow); BMessenger messenger(fWindow);
CopyEngine engine(messenger, new BMessage(MSG_STATUS_MESSAGE)); CopyEngine engine(messenger, new BMessage(MSG_STATUS_MESSAGE));
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) {
ERR("bad menu items\n"); ERR("bad menu items\n");
goto error; goto error;
@ -381,7 +381,12 @@ WorkerThread::_PerformInstall(BMenu *srcMenu, BMenu *targetMenu)
} }
if (entries != 0 if (entries != 0
&& ((new BAlert("", "The target volume is not empty. Are you sure you " && ((new BAlert("", "The target volume is not empty. Are you sure you "
"want to install anyway?", "Install Anyway", "Cancel", 0, "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.",
"Install Anyway", "Cancel", 0,
B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) { B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go() != 0)) {
err = B_CANCELED; err = B_CANCELED;
goto error; goto error;