fs: unguarded fs.watchFile cache statWatchers checking fixed
authorThomas Shinnick <tshinnic@gmail.com>
Fri, 9 Sep 2011 04:16:10 +0000 (23:16 -0500)
committerkoichik <koichik@improvement.jp>
Mon, 12 Sep 2011 06:59:00 +0000 (15:59 +0900)
Use hasOwnProperty to check filepath cache; previous code could fail if
a filepath duplicated a chained property name.

Fixes #1637.

lib/fs.js
test/simple/test-fs-watch-file.js

index 5a7f255..3ea945d 100644 (file)
--- a/lib/fs.js
+++ b/lib/fs.js
@@ -617,6 +617,9 @@ StatWatcher.prototype.stop = function() {
 
 
 var statWatchers = {};
+function inStatWatchers(filename) {
+  return Object.prototype.hasOwnProperty.call(statWatchers, filename);
+}
 
 
 fs.watchFile = function(filename) {
@@ -639,11 +642,10 @@ fs.watchFile = function(filename) {
   if (options.persistent === undefined) options.persistent = true;
   if (options.interval === undefined) options.interval = 0;
 
-  if (statWatchers[filename]) {
+  if (inStatWatchers(filename)) {
     stat = statWatchers[filename];
   } else {
-    statWatchers[filename] = new StatWatcher();
-    stat = statWatchers[filename];
+    stat = statWatchers[filename] = new StatWatcher();
     stat.start(filename, options.persistent, options.interval);
   }
   stat.addListener('change', listener);
@@ -652,7 +654,7 @@ fs.watchFile = function(filename) {
 
 fs.unwatchFile = function(filename) {
   var stat;
-  if (statWatchers[filename]) {
+  if (inStatWatchers(filename)) {
     stat = statWatchers[filename];
     stat.stop();
     statWatchers[filename] = undefined;
index ceee976..af91aeb 100644 (file)
@@ -27,13 +27,33 @@ var assert = require('assert');
 var path = require('path');
 var fs = require('fs');
 
+var watchSeenOne = 0;
+var watchSeenTwo = 0;
 
-var filename = path.join(common.fixturesDir, 'watch.txt');
-fs.writeFileSync(filename, "hello");
+var startDir = process.cwd();
+var testDir = common.fixturesDir;
+
+var filenameOne = 'watch.txt';
+var filepathOne = path.join(testDir, filenameOne);
+
+var filenameTwo = 'hasOwnProperty';
+var filepathTwo = filenameTwo;
+var filepathTwoAbs = path.join(testDir, filenameTwo);
+
+
+process.addListener('exit', function() {
+  fs.unlinkSync(filepathOne);
+  fs.unlinkSync(filepathTwoAbs);
+  assert.equal(1, watchSeenOne);
+  assert.equal(1, watchSeenTwo);
+});
+
+
+fs.writeFileSync(filepathOne, "hello");
 
 assert.throws(
   function() {
-    fs.watchFile(filename);
+    fs.watchFile(filepathOne);
   },
   function(e) {
     return e.message === 'watchFile requires a listener function';
@@ -42,14 +62,40 @@ assert.throws(
 
 assert.doesNotThrow(
   function() {
-    fs.watchFile(filename, function(curr, prev) {
-      fs.unwatchFile(filename);
-      fs.unlinkSync(filename);
+    fs.watchFile(filepathOne, function(curr, prev) {
+      fs.unwatchFile(filepathOne);
+      ++watchSeenOne;
     });
   }
 );
 
 setTimeout(function() {
-  fs.writeFileSync(filename, "world");
+  fs.writeFileSync(filepathOne, "world");
 }, 1000);
 
+
+process.chdir(testDir);
+
+fs.writeFileSync(filepathTwoAbs, "howdy");
+
+assert.throws(
+  function() {
+    fs.watchFile(filepathTwo);
+  },
+  function(e) {
+    return e.message === 'watchFile requires a listener function';
+  }
+);
+
+assert.doesNotThrow(
+  function() {
+    fs.watchFile(filepathTwo, function(curr, prev) {
+      fs.unwatchFile(filepathTwo);
+      ++watchSeenTwo;
+    });
+  }
+);
+
+setTimeout(function() {
+  fs.writeFileSync(filepathTwoAbs, "pardner");
+}, 1000);