diff --git a/lib/DirectoryWatcher.js b/lib/DirectoryWatcher.js index 54788ea..505d94a 100644 --- a/lib/DirectoryWatcher.js +++ b/lib/DirectoryWatcher.js @@ -61,6 +61,7 @@ class DirectoryWatcher extends EventEmitter { this.watcherManager = watcherManager; this.options = options; this.path = directoryPath; + this.watchingSymlink = false; // safeTime is the point in time after which reading is safe to be unchanged // timestamp is a value that should be compared with another timestamp (mtime) /** @type {Map { if (this.closed) return; if (err) { - if (err.code === "ENOENT" || err.code === "EPERM") { + if (this.watchingSymlink && err.code == "ENOTDIR") { + return; + } else if (err.code === "ENOENT" || err.code === "EPERM") { this.onDirectoryRemoved("scan readdir failed"); } else { this.onScanError(err); @@ -627,22 +630,7 @@ class DirectoryWatcher extends EventEmitter { } }); for (const itemPath of itemPaths) { - const handleStats = (err2, stats) => { - if (this.closed) return; - if (err2) { - if ( - err2.code === "ENOENT" || - err2.code === "EPERM" || - err2.code === "EACCES" || - err2.code === "EBUSY" - ) { - this.setMissing(itemPath, initial, "scan (" + err2.code + ")"); - } else { - this.onScanError(err2); - } - itemFinished(); - return; - } + const handleStats = (stats, symlinkStats) => { if (stats.isFile() || stats.isSymbolicLink()) { if (stats.mtime) { ensureFsAccuracy(stats.mtime); @@ -654,7 +642,11 @@ class DirectoryWatcher extends EventEmitter { true, "scan (file)" ); - } else if (stats.isDirectory()) { + } + if ( + stats.isDirectory() || + (symlinkStats && symlinkStats.isDirectory()) + ) { if (!initial || !this.directories.has(itemPath)) this.setDirectory( itemPath, @@ -665,11 +657,42 @@ class DirectoryWatcher extends EventEmitter { } itemFinished(); }; - if (this.watcherManager.options.followSymlinks) { - fs.stat(itemPath, handleStats); - } else { - fs.lstat(itemPath, handleStats); - } + fs.lstat(itemPath, (err2, stats) => { + if (this.closed) return; + if (err2) { + if ( + err2.code === "ENOENT" || + err2.code === "EPERM" || + err2.code === "EACCES" || + err2.code === "EBUSY" + ) { + this.setMissing(itemPath, initial, "scan (" + err2.code + ")"); + } else { + this.onScanError(err2); + } + itemFinished(); + return; + } + if ( + stats.isSymbolicLink() && + this.watcherManager.options.followSymlinks + ) { + fs.stat(itemPath, (err3, symlinkStats) => { + if (this.closed) return; + // something is wrong with the symlink, but not with the file itself + if (err3) { + handleStats(stats); + this.watchingSymlink = false; + return; + } + this.watchingSymlink = true; + handleStats(stats, symlinkStats); + }); + } else { + this.watchingSymlink = false; + handleStats(stats); + } + }); } itemFinished(); });