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:
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