From b8ee80e1fcf50de0599f5aab13ef9db482e83332 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Sun, 8 Oct 2017 19:59:56 -0400 Subject: [PATCH] Remove target directory in files.rename to avoid Windows EPERM errors. These errors are especially harmful because they cause files.rename to fall back to copying rather than atomically renaming, which is both much slower and not even remotely atomic. --- tools/fs/files.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/fs/files.js b/tools/fs/files.js index 8c3789c5ae..5dd318c269 100644 --- a/tools/fs/files.js +++ b/tools/fs/files.js @@ -1755,15 +1755,21 @@ files.existsSync = function (path, callback) { }; if (files.isWindowsLikeFilesystem()) { - var rename = files.rename; + const rename = files.rename; files.rename = function (from, to) { - // retries are necessarily only on Windows, because the rename call can fail - // with EBUSY, which means the file is "busy" - var maxTries = 10; - var success = false; + // Retries are necessary only on Windows, because the rename call can + // fail with EBUSY, which means the file is in use. + let maxTries = 10; + let success = false; + const osTo = files.convertToOSPath(to); + while (! success && maxTries-- > 0) { try { + // Despite previous failures, the top-level destination directory + // may have been successfully created, so we must remove it to + // avoid moving the source file *into* the destination directory. + rimraf.sync(osTo); rename(from, to); success = true; } catch (err) { @@ -1772,6 +1778,7 @@ if (files.isWindowsLikeFilesystem()) { } } } + if (! success) { files.cp_r(from, to); files.rm_recursive(from);