winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 8eb122897afbf237589927d05b7146b97c5e87d8
parent 9acb01b2fbc10ecc943ed56edf92c60084b95c66
Author: Ryan Fu <69221034+ryfu-msft@users.noreply.github.com>
Date:   Mon, 13 Mar 2023 17:36:00 -0700

Use copy instead of rename for moving extracted archive directories (#3003)


Diffstat:
Msrc/AppInstallerCLICore/PortableInstaller.cpp | 13+++++++++++--
Msrc/AppInstallerCLITests/Filesystem.cpp | 30++++++++++++++++++++++++++++++
Msrc/AppInstallerCommonCore/Filesystem.cpp | 13+++++++++++++
Msrc/AppInstallerCommonCore/Public/winget/Filesystem.h | 3+++
4 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/src/AppInstallerCLICore/PortableInstaller.cpp b/src/AppInstallerCLICore/PortableInstaller.cpp @@ -107,8 +107,17 @@ namespace AppInstaller::CLI::Portable } else if (fileType == PortableFileType::Directory) { - AICLI_LOG(Core, Info, << "Moving directory to: " << filePath); - Filesystem::RenameFile(entry.CurrentPath, filePath); + if (Filesystem::IsSameVolume(entry.CurrentPath, filePath)) + { + AICLI_LOG(Core, Info, << "Renaming directory to: " << filePath); + Filesystem::RenameFile(entry.CurrentPath, filePath); + } + else + { + // Copy directory instead of renaming as there is a known issue with renaming across drives. + AICLI_LOG(Core, Info, << "Copying directory to: " << filePath); + std::filesystem::copy(entry.CurrentPath, filePath, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive); + } } else if (entry.FileType == PortableFileType::Symlink) { diff --git a/src/AppInstallerCLITests/Filesystem.cpp b/src/AppInstallerCLITests/Filesystem.cpp @@ -56,4 +56,34 @@ TEST_CASE("VerifySymlink", "[filesystem]") std::filesystem::remove(symlinkPath); REQUIRE_FALSE(SymlinkExists(symlinkPath)); +} + +TEST_CASE("VerifyIsSameVolume", "[filesystem]") +{ + // Note: Pipeline build machine uses 'D:\' as the volume. + std::filesystem::path path1 = L"C:\\Program Files\\WinGet\\Packages"; + std::filesystem::path path2 = L"c:\\Users\\testUser\\AppData\\Local\\Microsoft\\WinGet\\Packages"; + std::filesystem::path path3 = L"localPath\\test\\folder"; + std::filesystem::path path4 = L"test\\folder"; + std::filesystem::path path5 = L"D:\\test\\folder"; + std::filesystem::path path6 = L"F:\\test\\folder"; + std::filesystem::path path7 = L"d:\\randomFolder"; + std::filesystem::path path8 = L"f:\\randomFolder"; + std::filesystem::path path9 = L"a"; + std::filesystem::path path10 = L"b"; + + // Verify that a relative path points to the current volume. + REQUIRE(IsSameVolume(path1, path2)); + REQUIRE(IsSameVolume(path5, path7)); + REQUIRE(IsSameVolume(path3, path4)); + REQUIRE(IsSameVolume(path9, path10)); + + REQUIRE_FALSE(IsSameVolume(path1, path5)); + REQUIRE_FALSE(IsSameVolume(path1, path6)); + REQUIRE_FALSE(IsSameVolume(path2, path5)); + REQUIRE_FALSE(IsSameVolume(path2, path6)); + REQUIRE_FALSE(IsSameVolume(path3, path6)); + REQUIRE_FALSE(IsSameVolume(path5, path6)); + REQUIRE_FALSE(IsSameVolume(path4, path6)); + REQUIRE_FALSE(IsSameVolume(path6, path8)); } \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Filesystem.cpp b/src/AppInstallerCommonCore/Filesystem.cpp @@ -238,4 +238,17 @@ namespace AppInstaller::Filesystem THROW_IF_FAILED(SHGetKnownFolderPath(id, KF_FLAG_NO_ALIAS | KF_FLAG_DONT_VERIFY | KF_FLAG_NO_PACKAGE_REDIRECTION, NULL, &knownFolder)); return knownFolder.get(); } + + bool IsSameVolume(const std::filesystem::path& path1, const std::filesystem::path& path2) + { + WCHAR volumeName1[MAX_PATH]; + WCHAR volumeName2[MAX_PATH]; + + // Note: GetVolumePathNameW will return false if the volume drive does not exist. + if (!GetVolumePathNameW(path1.c_str(), volumeName1, MAX_PATH) || !GetVolumePathNameW(path2.c_str(), volumeName2, MAX_PATH)) + { + return false; + } + return Utility::CaseInsensitiveEquals(Utility::ConvertToUTF8(volumeName1), Utility::ConvertToUTF8(volumeName2)); + } } \ No newline at end of file diff --git a/src/AppInstallerCommonCore/Public/winget/Filesystem.h b/src/AppInstallerCommonCore/Public/winget/Filesystem.h @@ -42,4 +42,7 @@ namespace AppInstaller::Filesystem // Gets the path of a known folder. std::filesystem::path GetKnownFolderPath(const KNOWNFOLDERID& id); + + // Verifies that the paths are on the same volume. + bool IsSameVolume(const std::filesystem::path& path1, const std::filesystem::path& path2); } \ No newline at end of file