diff --git a/src/apps/installer/CopyEngine.cpp b/src/apps/installer/CopyEngine.cpp index bd798fefae..7678facac8 100644 --- a/src/apps/installer/CopyEngine.cpp +++ b/src/apps/installer/CopyEngine.cpp @@ -128,16 +128,28 @@ CopyEngine::CollectTargets(const char* source, sem_id cancelSemaphore) status_t -CopyEngine::CopyFolder(const char* source, const char* destination, - sem_id cancelSemaphore) +CopyEngine::Copy(const char* _source, const char* _destination, + sem_id cancelSemaphore, bool copyAttributes) { int32 level = 0; - return _CopyFolder(source, destination, level, cancelSemaphore); + status_t ret; + + BEntry source(_source); + ret = source.InitCheck(); + if (ret != B_OK) + return ret; + + BEntry destination(_destination); + ret = destination.InitCheck(); + if (ret != B_OK) + return ret; + + return _Copy(source, destination, level, cancelSemaphore, copyAttributes); } status_t -CopyEngine::CopyFile(const BEntry& _source, const BEntry& _destination, +CopyEngine::_CopyData(const BEntry& _source, const BEntry& _destination, sem_id cancelSemaphore) { SemaphoreLocker lock(cancelSemaphore); @@ -282,157 +294,153 @@ CopyEngine::_CollectCopyInfo(const char* _source, int32& level, status_t -CopyEngine::_CopyFolder(const char* _source, const char* _destination, - int32& level, sem_id cancelSemaphore) +CopyEngine::_Copy(BEntry &source, BEntry &destination, + int32& level, sem_id cancelSemaphore, bool copyAttributes) { level++; - BDirectory source(_source); - status_t ret = source.InitCheck(); - if (ret < B_OK) + struct stat sourceInfo; + status_t ret = source.GetStat(&sourceInfo); + if (ret != B_OK) return ret; - ret = create_directory(_destination, 0777); - if (ret < B_OK && ret != B_FILE_EXISTS) { - fprintf(stderr, "Could not create '%s': %s\n", _destination, - strerror(ret)); - return ret; + SemaphoreLocker lock(cancelSemaphore); + if (cancelSemaphore >= 0 && !lock.IsLocked()) { + // We are supposed to quit + return B_CANCELED; } - BDirectory destination(_destination); - ret = destination.InitCheck(); - if (ret < B_OK) + BPath sourcePath(&source); + ret = sourcePath.InitCheck(); + if (ret != B_OK) return ret; - BEntry entry; - while (source.GetNextEntry(&entry) == B_OK) { - SemaphoreLocker lock(cancelSemaphore); - if (cancelSemaphore >= 0 && !lock.IsLocked()) { - // We are supposed to quit - return B_CANCELED; - } + BPath destPath(&destination); + ret = destPath.InitCheck(); + if (ret != B_OK) + return ret; - const char* name = entry.Name(); - BPath sourceEntryPath; - status_t ret = entry.GetPath(&sourceEntryPath); + const char *relativeSourcePath = _RelativeEntryPath(sourcePath.Path()); + if (fEntryFilter != NULL + && !fEntryFilter->ShouldCopyEntry(source, relativeSourcePath, + sourceInfo, level)) { + // Silently skip the filtered entry. + return B_OK; + } + + if (cancelSemaphore >= 0) + lock.Unlock(); + + if (S_ISDIR(sourceInfo.st_mode)) { + BDirectory sourceDirectory(&source); + ret = sourceDirectory.InitCheck(); if (ret != B_OK) return ret; - const char* relativeSourceEntryPath - = _RelativeEntryPath(sourceEntryPath.Path()); - struct stat statInfo; - entry.GetStat(&statInfo); + if (destination.Exists()) { + if (destination.IsDirectory()) { + if (fEntryFilter + && fEntryFilter->ShouldClobberFolder(source, + relativeSourcePath, sourceInfo, level)) { + ret = _RemoveFolder(destination); + } 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 = destination.Remove(); + } - if (fEntryFilter != NULL - && !fEntryFilter->ShouldCopyEntry(entry, relativeSourceEntryPath, - statInfo, level)) { - continue; + if (ret != B_OK) { + fprintf(stderr, "Failed to make room for folder '%s': " + "%s\n", sourcePath.Path(), strerror(ret)); + return ret; + } + } else { + ret = create_directory(destPath.Path(), 0777); + if (ret != B_OK && ret != B_FILE_EXISTS) { + fprintf(stderr, "Could not create '%s': %s\n", destPath.Path(), + strerror(ret)); + return ret; + } + } + + BDirectory destDirectory(&destination); + ret = destDirectory.InitCheck(); + if (ret != B_OK) + return ret; + + BEntry entry; + while (sourceDirectory.GetNextEntry(&entry) == B_OK) { + BEntry dest(&destDirectory, entry.Name()); + ret = dest.InitCheck(); + if (ret != B_OK) + return ret; + ret = _Copy(entry, dest, level, + cancelSemaphore, copyAttributes); + if (ret != B_OK) + return ret; + } + } else { + if (destination.Exists()) { + if (destination.IsDirectory()) + ret = _RemoveFolder(destination); + else + ret = destination.Remove(); + if (ret != B_OK) { + fprintf(stderr, "Failed to make room for entry '%s': " + "%s\n", sourcePath.Path(), strerror(ret)); + return ret; + } } fItemsCopied++; - fCurrentItem = name; - fCurrentTargetFolder = _destination; - _UpdateProgress(); - - BEntry copy(&destination, name); - bool copyAttributes = true; - - if (S_ISDIR(statInfo.st_mode)) { - // handle recursive directory copy - - if (copy.Exists()) { - ret = B_OK; - if (copy.IsDirectory()) { - if (fEntryFilter - && fEntryFilter->ShouldClobberFolder(entry, - relativeSourceEntryPath, statInfo, level)) { - 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 dstFolder; - ret = copy.GetPath(&dstFolder); - if (ret < B_OK) - return ret; - - if (cancelSemaphore >= 0) - lock.Unlock(); - - ret = _CopyFolder(sourceEntryPath.Path(), dstFolder.Path(), level, - cancelSemaphore); - if (ret < B_OK) - return ret; - - if (cancelSemaphore >= 0 && !lock.Lock()) { - // We are supposed to quit - return B_CANCELED; - } - } else { - if (copy.Exists()) { - if (copy.IsDirectory()) - ret = _RemoveFolder(copy); - else - 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) - continue; - - ret = copy.SetTo(&destination, name); + BPath destDirectory; + ret = destPath.GetParent(&destDirectory); if (ret != B_OK) return ret; + fCurrentTargetFolder = destDirectory.Path(); + fCurrentItem = sourcePath.Leaf(); + _UpdateProgress(); + if (S_ISLNK(sourceInfo.st_mode)) { + // copy symbolic links + BSymLink srcLink(&source); + ret = srcLink.InitCheck(); + 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; + + BDirectory dstFolder; + ret = destination.GetParent(&dstFolder); + if (ret != B_OK) + return ret; + ret = dstFolder.CreateSymLink(sourcePath.Leaf(), linkPath, NULL); + if (ret != B_OK) + return ret; + } else { + // copy file data + // NOTE: Do not pass the locker, we simply keep holding the lock! + ret = _CopyData(source, destination); + if (ret != B_OK) + return ret; + } + } + + if (copyAttributes) { // copy attributes - BNode sourceNode(&entry); - BNode targetNode(©); + BNode sourceNode(&source); + BNode targetNode(&destination); char attrName[B_ATTR_NAME_LENGTH]; while (sourceNode.GetNextAttrName(attrName) == B_OK) { attr_info info; - if (sourceNode.GetAttrInfo(attrName, &info) < B_OK) + if (sourceNode.GetAttrInfo(attrName, &info) != B_OK) continue; size_t size = 4096; uint8 buffer[size]; @@ -452,11 +460,11 @@ CopyEngine::_CopyFolder(const char* _source, const char* _destination, } // copy basic attributes - copy.SetPermissions(statInfo.st_mode); - copy.SetOwner(statInfo.st_uid); - copy.SetGroup(statInfo.st_gid); - copy.SetModificationTime(statInfo.st_mtime); - copy.SetCreationTime(statInfo.st_crtime); + destination.SetPermissions(sourceInfo.st_mode); + destination.SetOwner(sourceInfo.st_uid); + destination.SetGroup(sourceInfo.st_gid); + destination.SetModificationTime(sourceInfo.st_mtime); + destination.SetCreationTime(sourceInfo.st_crtime); } level--; diff --git a/src/apps/installer/CopyEngine.h b/src/apps/installer/CopyEngine.h index 298977225b..f988577cd5 100644 --- a/src/apps/installer/CopyEngine.h +++ b/src/apps/installer/CopyEngine.h @@ -32,20 +32,21 @@ public: status_t CollectTargets(const char* source, sem_id cancelSemaphore = -1); - status_t CopyFolder(const char* source, + status_t Copy(const char* source, const char* destination, - sem_id cancelSemaphore = -1); - - status_t CopyFile(const BEntry& entry, - const BEntry& destination, - sem_id cancelSemaphore = -1); + sem_id cancelSemaphore = -1, + bool copyAttributes = true); private: status_t _CollectCopyInfo(const char* source, int32& level, sem_id cancelSemaphore); - status_t _CopyFolder(const char* source, - const char* destination, - int32& level, sem_id cancelSemaphore); + status_t _Copy(BEntry& source, + BEntry& destination, + int32& level, sem_id cancelSemaphore, + bool copyAttributes); + status_t _CopyData(const BEntry& entry, + const BEntry& destination, + sem_id cancelSemaphore = -1); status_t _RemoveFolder(BEntry& entry); diff --git a/src/apps/installer/WorkerThread.cpp b/src/apps/installer/WorkerThread.cpp index f289f5bb4e..9cb87e0010 100644 --- a/src/apps/installer/WorkerThread.cpp +++ b/src/apps/installer/WorkerThread.cpp @@ -534,7 +534,7 @@ WorkerThread::_PerformInstall(partition_id sourcePartitionID, reporter.StartTimer(); // copy source volume - err = engine.CopyFolder(srcDirectory.Path(), targetDirectory.Path(), + err = engine.Copy(srcDirectory.Path(), targetDirectory.Path(), fCancelSemaphore); if (err != B_OK) return _InstallationError(err); @@ -546,7 +546,7 @@ WorkerThread::_PerformInstall(partition_id sourcePartitionID, for (int32 i = 0; i < count; i++) { Package *p = static_cast(fPackages->ItemAt(i)); BPath packageDir(pkgRootDir.Path(), p->Folder()); - err = engine.CopyFolder(packageDir.Path(), targetDirectory.Path(), + err = engine.Copy(packageDir.Path(), targetDirectory.Path(), fCancelSemaphore); if (err != B_OK) return _InstallationError(err);