Skip to content

Race condition when 2 calls copying files to the same nonexistent directory #141

@Soulike

Description

@Soulike

This may be a same bug as #125.

The test case:

const tmpDir = path.join(os.tmpdir(), 'testFolder');

fs.rmSync(tmpDir, {recursive: true, force: true});

// operation A
ncp('./bin', tmpDir, function (err)
{
    if (err)
    {
        return console.error(err);
    }
    console.log('done!');
});

// operation B
ncp('./lib', tmpDir, function (err)
{
    if (err)
    {
        return console.error(err);
    }
    console.log('done!');
});

The execution result is:

[
  [Error: EEXIST: file already exists, mkdir '/tmp/testFolder'] {
    errno: -17,
    code: 'EEXIST',
    syscall: 'mkdir',
    path: '/tmp/testFolder'
  }
]
done!

Both operation A and B first checks the existence of tmpDir and thought tmpDir does not exist. Then both of them will try to create it. One of A and B will success and the other will fail.

The root cause is that the asynchronous call sequence isWritable() -> rmFile() may be violated by another call to ncp()

ncp/lib/ncp.js

Lines 221 to 229 in 6820b0f

function isWritable(path, done) {
fs.lstat(path, function (err) {
if (err) {
if (err.code === 'ENOENT') return done(true);
return done(false);
}
return done(false);
});
}

ncp/lib/ncp.js

Lines 148 to 151 in 6820b0f

isWritable(target, function (writable) {
if (writable) {
return mkDir(dir, target);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions