Skip to content

Commit

Permalink
win32 rename EPERM: fail fast if target exists
Browse files Browse the repository at this point in the history
When `rename` is used on Windows, and encounters an EPERM or EACCES
error, graceful-fs will retry for up to 30 seconds with gradual backoff
to get around file system locking due to A/V etc.

This was fixed in 59145ce

However, this is a problem if the target exists, which can cause an
EPERM or EACCES that is not due to folder locking.

This commit causes it to fail fast when an EPERM or EACCES is
raised by rename if the target exists.

Fix #98
  • Loading branch information
isaacs committed Nov 16, 2016
1 parent db8df44 commit 90a96bc
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 2 deletions.
12 changes: 10 additions & 2 deletions polyfills.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ var constants = require('constants')

var origCwd = process.cwd
var cwd = null

var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform

process.cwd = function() {
if (!cwd)
cwd = origCwd.call(process)
Expand Down Expand Up @@ -87,7 +90,7 @@ function patch (fs) {
// failures. Also, take care to yield the scheduler. Windows scheduling gives
// CPU to a busy looping process, which can cause the program causing the lock
// contention to be starved of CPU by node, so the contention doesn't resolve.
if (process.platform === "win32") {
if (platform === "win32") {
fs.rename = (function (fs$rename) { return function (from, to, cb) {
var start = Date.now()
var backoff = 0;
Expand All @@ -96,7 +99,12 @@ function patch (fs) {
&& (er.code === "EACCES" || er.code === "EPERM")
&& Date.now() - start < 60000) {
setTimeout(function() {
fs$rename(from, to, CB);
fs.stat(to, function (stater, st) {
if (stater && stater.code === "ENOENT")
fs$rename(from, to, CB);
else
cb(er)
})
}, backoff)
if (backoff < 100)
backoff += 10;
Expand Down
35 changes: 35 additions & 0 deletions test/windows-rename-polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
process.env.GRACEFUL_FS_PLATFORM = 'win32'

var fs = require('fs')
fs.rename = function (a, b, cb) {
setTimeout(function () {
var er = new Error('EPERM blerg')
er.code = 'EPERM'
cb(er)
})
}

var gfs = require('../')
var t = require('tap')
var a = __dirname + '/a'
var b = __dirname + '/b'

t.test('setup', function (t) {
try { fs.mkdirSync(a) } catch (e) {}
try { fs.mkdirSync(b) } catch (e) {}
t.end()
})

t.test('rename', { timeout: 100 }, function (t) {
t.plan(1)

gfs.rename(a, b, function (er) {
t.ok(er)
})
})

t.test('cleanup', function (t) {
try { fs.rmdirSync(a) } catch (e) {}
try { fs.rmdirSync(b) } catch (e) {}
t.end()
})

0 comments on commit 90a96bc

Please sign in to comment.