Skip to content

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

@Soulike

Description

@Soulike

The bug is similar to #141 but applies to files.
Before copying a file, ncp first checks whether the target file exists. If it exists (writable is false), ncp will delete it and start copying.

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 84 to 97 in 6820b0f

function onFile(file) {
var target = file.name.replace(currentPath, targetPath);
if(rename) {
target = rename(target);
}
isWritable(target, function (writable) {
if (writable) {
return copyFile(file, target);
}
if(clobber) {
rmFile(target, function () {
copyFile(file, target);
});
}

So if 2 calls of ncp(), which copy files to the same directory, executes at almost the same time, the overwritten files in the target directory may be delete twice, and the latter one will throw error.

The test case below can reproduce the bug:

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

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

ncp(sourceDir, tmpDir, function (err)
{
    if (err)
    {
        return console.error(err);
    }
    console.log('done!');

    ncp(sourceDir, tmpDir, function (err)
    {
        if (err)
        {
            return console.error(err);
        }
        console.log('done!');
    });

    ncp(sourceDir, tmpDir, function (err)
    {
        if (err)
        {
            return console.error(err);
        }
        console.log('done!');
    });
});

The execution result:

done!
[
   [Error: ENOENT: no such file or directory, unlink '/tmp/testFolder/xxxxx']
   [Error: ENOENT: no such file or directory, unlink '/tmp/testFolder/xxxxx']
    ...
]
done!

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