Skip to content

Commit

Permalink
fix: Rescan directory after setting up watch to prevent a race
Browse files Browse the repository at this point in the history
Sometimes, when another process just happened to create a file
when we were setting up a watch, the new file wouldn't be noticed.

To prevent the event not being generated in this case, schedule
a directory rescan immediately after setting up a watch.

Fixes paulmillr#1112
  • Loading branch information
dividedmind committed Jul 10, 2022
1 parent 6bdda7f commit 4f54121
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/nodefs-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,11 @@ async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath) {

this._handleRead(dirPath, false, wh, target, dir, depth, throttler);
});

// schedule a rescan of the directory in case something
// appeared while we were setting up the watch
if (!(this.fsw.usePolling || target || this.fsw.closed))
this._handleRead(dir, false, wh, target, dir, depth, throttler);
}
return closer;
}
Expand Down
23 changes: 23 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,29 @@ const runTests = (baseopts) => {
expect(spy.args[0][1]).to.be.ok; // stats
rawSpy.should.have.been.called;
});
if (!(baseopts.usePolling || baseopts.useFsEvents)) context('when a race happens', () => {
beforeEach(() => {
const stub = sinon.stub(fs, 'watch');
stub.callsFake((filename, ...rest) => {
// pretend a sneaky process creates a file just as we're about to set up the watch
if (filename.endsWith('subdir')) fs.writeFileSync(getFixturePath('subdir/add.txt'), dateNow());
return stub.wrappedMethod(filename, ...rest);
});
});
afterEach(() => fs.watch.restore());
it('should notice when a file appears in a new directory anyway', async () => {
const testDir = getFixturePath('subdir');
const testPath = getFixturePath('subdir/add.txt');
const spy = await aspy(watcher, EV_ADD);
spy.should.not.have.been.called;
await fs_mkdir(testDir, PERM_ARR);
await waitFor([spy]);
spy.should.have.been.calledOnce;
spy.should.have.been.calledWith(testPath);
expect(spy.args[0][1]).to.be.ok; // stats
rawSpy.should.have.been.called;
});
});
it('should watch removed and re-added directories', async () => {
const unlinkSpy = sinon.spy(function unlinkSpy(){});
const addSpy = sinon.spy(function addSpy(){});
Expand Down

0 comments on commit 4f54121

Please sign in to comment.