diff --git a/README.md b/README.md
index 1b3b4a4..6f7304e 100644
--- a/README.md
+++ b/README.md
@@ -175,7 +175,7 @@ interface as providers. See the code in `src/providers` and `src/adapters` for
The node.js [path module](http://nodejs.org/api/path.html) is available via the `Filer.Path` object. It is
identical to the node.js version with the following differences:
-* No support for `exits()` or `existsSync()`. Use `fs.stat()` instead.
+* No support for `existsSync()`. Use `fs.stat()` instead.
* No notion of a current working directory in `resolve` (the root dir is used instead)
```javascript
@@ -219,6 +219,7 @@ var fs = new Filer.FileSystem();
* [fs.stat(path, callback)](#stat)
* [fs.fstat(fd, callback)](#fstat)
* [fs.lstat(path, callback)](#lstat)
+* [fs.exists(path, callback)](#exists)
* [fs.link(srcpath, dstpath, callback)](#link)
* [fs.symlink(srcpath, dstpath, [type], callback)](#symlink)
* [fs.readlink(path, callback)](#readlink)
@@ -417,7 +418,25 @@ fs.link("/data/logs/august", "/data/logs/current", function(err) {
var size = stats.size;
});
});
-````
+```
+
+#### fs.exists(path, callback)
+
+Test whether or not the given path exists by checking with the file system.
+Then call the callback argument with either true or false.
+
+Example:
+
+```javascript
+//Test if the file exists
+fs.exists('/myfile', function (exists) {
+ console.log(exists ? "file exists" : "file not found");
+});
+```
+
+fs.exists() is an anachronism and exists only for historical reasons. There should almost never be a reason to use it in your own code.
+
+In particular, checking if a file exists before opening it is an anti-pattern that leaves you vulnerable to race conditions: another process may remove the file between the calls to fs.exists() and fs.open(). Just open the file and handle the error when it's not there.
#### fs.link(srcPath, dstPath, callback)
diff --git a/src/fs.js b/src/fs.js
index 122ce21..2bcf1d3 100644
--- a/src/fs.js
+++ b/src/fs.js
@@ -1789,6 +1789,13 @@ define(function(require) {
});
}
+ function _exists (context, name, path, callback) {
+ function cb(err, stats) {
+ callback(err ? false : true);
+ }
+ _stat(context, name, path, cb);
+ }
+
function _getxattr (context, path, name, callback) {
if (!nullCheck(path, callback)) return;
@@ -2265,6 +2272,17 @@ define(function(require) {
);
if(error) callback(error);
};
+ FileSystem.prototype.exists = function(path, callback_) {
+ var callback = maybeCallback(arguments[arguments.length - 1]);
+ var fs = this;
+ var error = fs.queueOrRun(
+ function() {
+ var context = fs.provider.getReadOnlyContext();
+ _exists(context, fs.name, path, callback);
+ }
+ );
+ if(error) callback(error);
+ };
FileSystem.prototype.lseek = function(fd, offset, whence, callback) {
callback = maybeCallback(callback);
var fs = this;
diff --git a/tests/spec/fs.exists.spec.js b/tests/spec/fs.exists.spec.js
new file mode 100644
index 0000000..ff8bc03
--- /dev/null
+++ b/tests/spec/fs.exists.spec.js
@@ -0,0 +1,56 @@
+define(["Filer", "util"], function(Filer, util) {
+
+ describe('fs.exists', function() {
+ beforeEach(util.setup);
+ afterEach(util.cleanup);
+
+ it('should be a function', function() {
+ var fs = util.fs();
+ expect(typeof fs.exists).to.equal('function');
+ });
+
+ it('should return false if path does not exist', function(done) {
+ var fs = util.fs();
+ fs.exists('/tmp', function(result) {
+ expect(result).to.exist;
+ expect(result).equals(false);
+ done();
+ });
+ });
+
+ it('should return true if path exists', function(done) {
+ var fs = util.fs();
+
+ fs.open('/myfile', 'w', function(err, fd) {
+ if(err) throw err;
+ fs.close(fd, function(err) {
+ if(err) throw err;
+ fs.exists('/myfile', function(result) {
+ expect(result).to.exist;
+ expect(result).equals(true);
+ done();
+ });
+ });
+ });
+ });
+
+ it('should follow symbolic links and return true for the resulting path', function(done) {
+ var fs = util.fs();
+
+ fs.open('/myfile', 'w', function(error, fd) {
+ if(error) throw error;
+ fs.close(fd, function(error) {
+ if(error) throw error;
+ fs.symlink('/myfile', '/myfilelink', function(error) {
+ if(error) throw error;
+ fs.exists('/myfilelink', function(result) {
+ expect(result).to.exist;
+ expect(result).equals(true);
+ done();
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/tests/test-manifest.js b/tests/test-manifest.js
index 3b903a6..026c4b7 100644
--- a/tests/test-manifest.js
+++ b/tests/test-manifest.js
@@ -12,6 +12,7 @@ define([
"spec/fs.spec",
"spec/fs.stat.spec",
"spec/fs.lstat.spec",
+ "spec/fs.exists.spec",
"spec/fs.mkdir.spec",
"spec/fs.readdir.spec",
"spec/fs.rmdir.spec",