summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2022-11-17 18:27:21 (GMT)
committerBrad King <brad.king@kitware.com>2022-11-17 20:05:07 (GMT)
commitefa9eec0402adacc7ac8b0dc17660a8bd968b06a (patch)
tree4faf3121039e17ea3d951912b2aede27ef939f1e /Source
parentfa518188d8aeffa176109bc960173b06fa1e135e (diff)
downloadCMake-efa9eec0402adacc7ac8b0dc17660a8bd968b06a.zip
CMake-efa9eec0402adacc7ac8b0dc17660a8bd968b06a.tar.gz
CMake-efa9eec0402adacc7ac8b0dc17660a8bd968b06a.tar.bz2
file(COPY_FILE): Add option to retry on Windows if input access fails
On Windows, a file may be inaccessible for a short time after it is created. This occurs for various reasons, including indexing, antivirus tools, and NTFS's asynchronous semantics. Add an `INPUT_MAY_BE_RECENT` option to tell CMake that the input file may have been recently created so that we can retry a few times to read it.
Diffstat (limited to 'Source')
-rw-r--r--Source/cmFileCommand.cxx8
-rw-r--r--Source/cmSystemTools.cxx19
-rw-r--r--Source/cmSystemTools.h6
3 files changed, 31 insertions, 2 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index 85f528d..cdd0408 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -1408,12 +1408,14 @@ bool HandleCopyFile(std::vector<std::string> const& args,
struct Arguments
{
+ bool InputMayBeRecent = false;
bool OnlyIfDifferent = false;
std::string Result;
};
static auto const parser =
cmArgumentParser<Arguments>{}
+ .Bind("INPUT_MAY_BE_RECENT"_s, &Arguments::InputMayBeRecent)
.Bind("ONLY_IF_DIFFERENT"_s, &Arguments::OnlyIfDifferent)
.Bind("RESULT"_s, &Arguments::Result);
@@ -1456,9 +1458,13 @@ bool HandleCopyFile(std::vector<std::string> const& args,
} else {
when = cmSystemTools::CopyWhen::Always;
}
+ cmSystemTools::CopyInputRecent const inputRecent = arguments.InputMayBeRecent
+ ? cmSystemTools::CopyInputRecent::Yes
+ : cmSystemTools::CopyInputRecent::No;
std::string err;
- if (cmSystemTools::CopySingleFile(oldname, newname, when, &err) ==
+ if (cmSystemTools::CopySingleFile(oldname, newname, when, inputRecent,
+ &err) ==
cmSystemTools::CopyResult::Success) {
if (!arguments.Result.empty()) {
status.GetMakefile().AddDefinition(arguments.Result, "0");
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 75b7668..f94c4d3 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -1113,7 +1113,7 @@ bool cmMoveFile(std::wstring const& oldname, std::wstring const& newname,
cmSystemTools::CopyResult cmSystemTools::CopySingleFile(
std::string const& oldname, std::string const& newname, CopyWhen when,
- std::string* err)
+ CopyInputRecent inputRecent, std::string* err)
{
switch (when) {
case CopyWhen::Always:
@@ -1137,7 +1137,24 @@ cmSystemTools::CopyResult cmSystemTools::CopySingleFile(
status = cmsys::SystemTools::CloneFileContent(oldname, newname);
if (!status) {
// if cloning did not succeed, fall back to blockwise copy
+#ifdef _WIN32
+ if (inputRecent == CopyInputRecent::Yes) {
+ // Windows sometimes locks a file immediately after creation.
+ // Retry a few times.
+ WindowsFileRetry retry = cmSystemTools::GetWindowsFileRetry();
+ while ((status =
+ cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname),
+ status.Path == cmsys::SystemTools::CopyStatus::SourcePath &&
+ status.GetPOSIX() == EACCES && --retry.Count)) {
+ cmSystemTools::Delay(retry.Delay);
+ }
+ } else {
+ status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname);
+ }
+#else
+ static_cast<void>(inputRecent);
status = cmsys::SystemTools::CopyFileContentBlockwise(oldname, newname);
+#endif
}
if (!status) {
if (err) {
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index f2b3dd2..09f2bf0 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -149,6 +149,11 @@ public:
Always,
OnlyIfDifferent,
};
+ enum class CopyInputRecent
+ {
+ No,
+ Yes,
+ };
enum class CopyResult
{
Success,
@@ -179,6 +184,7 @@ public:
/** Copy a file. */
static CopyResult CopySingleFile(std::string const& oldname,
std::string const& newname, CopyWhen when,
+ CopyInputRecent inputRecent,
std::string* err = nullptr);
enum class Replace