From dbd9afb6ecf7eaa8cadaec1a99e60d56770ce9fc Mon Sep 17 00:00:00 2001 From: Albert Siddhartha Slawinski Date: Wed, 13 Aug 2014 10:43:03 -0700 Subject: [PATCH] fs.stat third parameter controlling error creation In some environment (especially when coffescript is involved) module.js will spend a lot of time looking up nonexisting files. This is caused by the lengthy error creation. Those errors are then immediately caught. This change makes the lookup much faster, by avoiding the unnecessary error creation. module::statPath now uses the new second parameter of fs.statSync function of the fs.js. There is a similar change for the fs.stat, adding the third parameter. Apply suggestions from libuv pull request Thanks saghul: https://github.com/joyent/libuv/pull/1428 Fix the datastructures for async Documentation update Add tests and simplify Stat function Apply the code review comments --- doc/api/fs.markdown | 10 +- lib/fs.js | 66 +++++++----- lib/module.js | 6 +- src/node_file.cc | 151 +++++++++++++++------------ src/node_file.h | 6 ++ test/simple/test-fs-stat-sync.js | 168 +++++++++++++++++++++++++++++++ test/simple/test-fs-stat.js | 65 ++++++++---- 7 files changed, 358 insertions(+), 114 deletions(-) create mode 100644 test/simple/test-fs-stat-sync.js diff --git a/doc/api/fs.markdown b/doc/api/fs.markdown index f886b73dc7e9..380820cb39e0 100644 --- a/doc/api/fs.markdown +++ b/doc/api/fs.markdown @@ -153,12 +153,15 @@ Only available on Mac OS X. Synchronous lchmod(2). -## fs.stat(path, callback) +## fs.stat(path, callback, [throwSafe]) Asynchronous stat(2). The callback gets two arguments `(err, stats)` where `stats` is a [fs.Stats](#fs_class_fs_stats) object. See the [fs.Stats](#fs_class_fs_stats) section below for more information. +The throwSafe parameter if set to true prevents the error creation. If the call +fails, the first parameter of the callback will be true. + ## fs.lstat(path, callback) Asynchronous lstat(2). The callback gets two arguments `(err, stats)` where @@ -172,10 +175,13 @@ Asynchronous fstat(2). The callback gets two arguments `(err, stats)` where `stats` is a `fs.Stats` object. `fstat()` is identical to `stat()`, except that the file to be stat-ed is specified by the file descriptor `fd`. -## fs.statSync(path) +## fs.statSync(path, [throwSafe]) Synchronous stat(2). Returns an instance of `fs.Stats`. +The throwSafe parameter if set to true prevents the error creation. If the call +fails, the first parameter of the callback will be true. + ## fs.lstatSync(path) Synchronous lstat(2). Returns an instance of `fs.Stats`. diff --git a/lib/fs.js b/lib/fs.js index 1e3dc6415a62..2b04ce2006bd 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -114,14 +114,16 @@ function assertEncoding(encoding) { } } -function nullCheck(path, callback) { +function nullCheck(path, callback, throwSafe) { if (('' + path).indexOf('\u0000') !== -1) { - var er = new Error('Path must be a string without null bytes.'); - if (!callback) - throw er; - process.nextTick(function() { - callback(er); - }); + if (!throwSafe) { + var er = new Error('Path must be a string without null bytes.'); + if (!callback) + throw er; + process.nextTick(function() { + callback(er); + }); + } return false; } return true; @@ -162,21 +164,30 @@ fs.Stats.prototype.isSocket = function() { }; fs.exists = function(path, callback) { - if (!nullCheck(path, cb)) return; - binding.stat(pathModule._makeLong(path), cb); - function cb(err, stats) { - if (callback) callback(err ? false : true); + if (!nullCheck(path, undefined, true)) { + process.nextTick(function() { + cb(true, false); + }); + return; + } + binding.stat(pathModule._makeLong(path), cb, true); + function cb(err, result) { + if (callback) { + if (err) { + callback(false); + } else { + callback(!!result); + } + } } }; fs.existsSync = function(path) { - try { - nullCheck(path); - binding.stat(pathModule._makeLong(path)); - return true; - } catch (e) { + if (!nullCheck(path, undefined, true)) return false; - } + if (!binding.stat(pathModule._makeLong(path), undefined, true)) + return false; + return true; }; fs.readFile = function(path, options, callback_) { @@ -675,10 +686,17 @@ fs.lstat = function(path, callback) { binding.lstat(pathModule._makeLong(path), callback); }; -fs.stat = function(path, callback) { +fs.stat = function(path, callback, throwSafe) { callback = makeCallback(callback); - if (!nullCheck(path, callback)) return; - binding.stat(pathModule._makeLong(path), callback); + if (!nullCheck(path, callback, throwSafe)) { + if (throwSafe) { + process.nextTick(function() { + callback(true, false); + }); + } + return; + } + binding.stat(pathModule._makeLong(path), callback, throwSafe); }; fs.fstatSync = function(fd) { @@ -690,9 +708,11 @@ fs.lstatSync = function(path) { return binding.lstat(pathModule._makeLong(path)); }; -fs.statSync = function(path) { - nullCheck(path); - return binding.stat(pathModule._makeLong(path)); +fs.statSync = function(path, throwSafe) { + if (!nullCheck(path, undefined, throwSafe)) + return false; + + return binding.stat(pathModule._makeLong(path), undefined, throwSafe); }; fs.readlink = function(path, callback) { diff --git a/lib/module.js b/lib/module.js index edca95bd4e04..5d3f2fbc1f3b 100644 --- a/lib/module.js +++ b/lib/module.js @@ -87,10 +87,8 @@ var debug = Module._debug; function statPath(path) { var fs = NativeModule.require('fs'); - try { - return fs.statSync(path); - } catch (ex) {} - return false; + + return fs.statSync(path, true); } // check if the directory is a package.json dir diff --git a/src/node_file.cc b/src/node_file.cc index 3c35e0b4ffad..d6589ab03225 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -49,7 +49,7 @@ using namespace v8; #define THROW_BAD_ARGS TYPE_ERROR("Bad argument") -class FSReqWrap: public ReqWrap { +class FSReqWrap: public ReqWrap { public: void* operator new(size_t size, char* storage) { return storage; } @@ -92,8 +92,10 @@ static inline bool IsInt64(double x) { static void After(uv_fs_t *req) { HandleScope scope; - FSReqWrap* req_wrap = (FSReqWrap*) req->data; - assert(&req_wrap->req_ == req); + node_fs_t* req_node = (node_fs_t*) req; + + FSReqWrap* req_wrap = (FSReqWrap*) req_node->data; + assert(&req_wrap->req_.req == req); // there is always at least one argument. "error" int argc = 1; @@ -107,7 +109,11 @@ static void After(uv_fs_t *req) { if (req->result == -1) { // If the request doesn't have a path parameter set. - if (!req->path) { + if (req_node->throwSafe == 1) { + argc = 2; + argv[0] = Local::New(True()); + argv[1] = Local::New(False()); + } else if (!req->path) { argv[0] = UVException(req->errorno, NULL, req_wrap->syscall()); @@ -125,6 +131,7 @@ static void After(uv_fs_t *req) { req_wrap->syscall(), static_cast(req->path)); } + } else { // error value is empty or null for non-error. argv[0] = Local::New(Null()); @@ -213,7 +220,7 @@ static void After(uv_fs_t *req) { } MakeCallback(req_wrap->object_, oncomplete_sym, argc, argv); - uv_fs_req_cleanup(&req_wrap->req_); + uv_fs_req_cleanup(&req_wrap->req_.req); delete req_wrap; } @@ -221,15 +228,16 @@ static void After(uv_fs_t *req) { // For async calls FSReqWrap is used. struct fs_req_wrap { fs_req_wrap() {} - ~fs_req_wrap() { uv_fs_req_cleanup(&req); } + ~fs_req_wrap() { uv_fs_req_cleanup(&req.req); } // Ensure that copy ctor and assignment operator are not used. fs_req_wrap(const fs_req_wrap& req); fs_req_wrap& operator=(const fs_req_wrap& req); - uv_fs_t req; + node_fs_t req; }; -#define ASYNC_DEST_CALL(func, callback, dest_path, ...) \ +#define ASYNC_DEST_CALL(func, callback, dest_path, \ + throwSafeValue, ...) \ FSReqWrap* req_wrap; \ char* dest_str = (dest_path); \ int dest_len = dest_str == NULL ? 0 : strlen(dest_str); \ @@ -241,14 +249,15 @@ struct fs_req_wrap { dest_str, \ dest_len + 1); \ } \ + req_wrap->req_.throwSafe = throwSafeValue; \ int r = uv_fs_##func(uv_default_loop(), \ - &req_wrap->req_, \ + &req_wrap->req_.req, \ __VA_ARGS__, \ After); \ req_wrap->object_->Set(oncomplete_sym, callback); \ req_wrap->Dispatched(); \ if (r < 0) { \ - uv_fs_t* req = &req_wrap->req_; \ + uv_fs_t* req = &req_wrap->req_.req; \ req->result = r; \ req->path = NULL; \ req->errorno = uv_last_error(uv_default_loop()).code; \ @@ -256,16 +265,21 @@ struct fs_req_wrap { } \ return scope.Close(req_wrap->object_); -#define ASYNC_CALL(func, callback, ...) \ - ASYNC_DEST_CALL(func, callback, NULL, __VA_ARGS__) \ +#define ASYNC_CALL(func, callback, throwSafeValue, ...) \ + ASYNC_DEST_CALL(func, callback, NULL, throwSafeValue, \ + __VA_ARGS__) \ -#define SYNC_DEST_CALL(func, path, dest, ...) \ +#define SYNC_DEST_CALL(func, path, dest, throwSafeValue, ...) \ fs_req_wrap req_wrap; \ + req_wrap.req.throwSafe = throwSafeValue; \ int result = uv_fs_##func(uv_default_loop(), \ - &req_wrap.req, \ + &req_wrap.req.req, \ __VA_ARGS__, \ NULL); \ if (result < 0) { \ + if (req_wrap.req.throwSafe == 1) { \ + return False(); \ + } \ int code = uv_last_error(uv_default_loop()).code; \ if (dest != NULL && \ (code == UV_EEXIST || \ @@ -277,10 +291,10 @@ struct fs_req_wrap { } \ } \ -#define SYNC_CALL(func, path, ...) \ - SYNC_DEST_CALL(func, path, NULL, __VA_ARGS__) \ +#define SYNC_CALL(func, path, throwSafeValue, ...) \ + SYNC_DEST_CALL(func, path, NULL, throwSafeValue, __VA_ARGS__) \ -#define SYNC_REQ req_wrap.req +#define SYNC_REQ req_wrap.req.req #define SYNC_RESULT result @@ -295,9 +309,9 @@ static Handle Close(const Arguments& args) { int fd = args[0]->Int32Value(); if (args[1]->IsFunction()) { - ASYNC_CALL(close, args[1], fd) + ASYNC_CALL(close, args[1], 0, fd) } else { - SYNC_CALL(close, 0, fd) + SYNC_CALL(close, 0, 0, fd) return Undefined(); } } @@ -406,10 +420,15 @@ static Handle Stat(const Arguments& args) { node::Utf8Value path(args[0]); + int throwSafe = 0; + if (args[2]->IsTrue()) { + throwSafe = 1; + } + if (args[1]->IsFunction()) { - ASYNC_CALL(stat, args[1], *path) + ASYNC_CALL(stat, args[1], throwSafe, *path) } else { - SYNC_CALL(stat, *path, *path) + SYNC_CALL(stat, *path, throwSafe, *path) return scope.Close( BuildStatsObject(static_cast(SYNC_REQ.ptr))); } @@ -424,9 +443,9 @@ static Handle LStat(const Arguments& args) { node::Utf8Value path(args[0]); if (args[1]->IsFunction()) { - ASYNC_CALL(lstat, args[1], *path) + ASYNC_CALL(lstat, args[1], 0, *path) } else { - SYNC_CALL(lstat, *path, *path) + SYNC_CALL(lstat, *path, 0, *path) return scope.Close( BuildStatsObject(static_cast(SYNC_REQ.ptr))); } @@ -442,9 +461,9 @@ static Handle FStat(const Arguments& args) { int fd = args[0]->Int32Value(); if (args[1]->IsFunction()) { - ASYNC_CALL(fstat, args[1], fd) + ASYNC_CALL(fstat, args[1], 0, fd) } else { - SYNC_CALL(fstat, 0, fd) + SYNC_CALL(fstat, 0, 0, fd) return scope.Close( BuildStatsObject(static_cast(SYNC_REQ.ptr))); } @@ -476,9 +495,9 @@ static Handle Symlink(const Arguments& args) { } if (args[3]->IsFunction()) { - ASYNC_DEST_CALL(symlink, args[3], *dest, *dest, *path, flags) + ASYNC_DEST_CALL(symlink, args[3], *dest, 0, *dest, *path, flags) } else { - SYNC_DEST_CALL(symlink, *path, *dest, *dest, *path, flags) + SYNC_DEST_CALL(symlink, *path, *dest, 0, *dest, *path, flags) return Undefined(); } } @@ -496,9 +515,9 @@ static Handle Link(const Arguments& args) { node::Utf8Value new_path(args[1]); if (args[2]->IsFunction()) { - ASYNC_DEST_CALL(link, args[2], *new_path, *orig_path, *new_path) + ASYNC_DEST_CALL(link, args[2], *new_path, 0, *orig_path, *new_path) } else { - SYNC_DEST_CALL(link, *orig_path, *new_path, *orig_path, *new_path) + SYNC_DEST_CALL(link, *orig_path, *new_path, 0, *orig_path, *new_path) return Undefined(); } } @@ -512,9 +531,9 @@ static Handle ReadLink(const Arguments& args) { node::Utf8Value path(args[0]); if (args[1]->IsFunction()) { - ASYNC_CALL(readlink, args[1], *path) + ASYNC_CALL(readlink, args[1], 0, *path) } else { - SYNC_CALL(readlink, *path, *path) + SYNC_CALL(readlink, *path, 0, *path) return scope.Close(String::New((char*)SYNC_REQ.ptr)); } } @@ -532,9 +551,9 @@ static Handle Rename(const Arguments& args) { node::Utf8Value new_path(args[1]); if (args[2]->IsFunction()) { - ASYNC_DEST_CALL(rename, args[2], *new_path, *old_path, *new_path) + ASYNC_DEST_CALL(rename, args[2], *new_path, 0, *old_path, *new_path) } else { - SYNC_DEST_CALL(rename, *old_path, *new_path, *old_path, *new_path) + SYNC_DEST_CALL(rename, *old_path, *new_path, 0, *old_path, *new_path) return Undefined(); } } @@ -552,9 +571,9 @@ static Handle FTruncate(const Arguments& args) { int64_t len = GET_TRUNCATE_LENGTH(args[1]); if (args[2]->IsFunction()) { - ASYNC_CALL(ftruncate, args[2], fd, len) + ASYNC_CALL(ftruncate, args[2], 0, fd, len) } else { - SYNC_CALL(ftruncate, 0, fd, len) + SYNC_CALL(ftruncate, 0, 0, fd, len) return Undefined(); } } @@ -569,9 +588,9 @@ static Handle Fdatasync(const Arguments& args) { int fd = args[0]->Int32Value(); if (args[1]->IsFunction()) { - ASYNC_CALL(fdatasync, args[1], fd) + ASYNC_CALL(fdatasync, args[1], 0, fd) } else { - SYNC_CALL(fdatasync, 0, fd) + SYNC_CALL(fdatasync, 0, 0, fd) return Undefined(); } } @@ -586,9 +605,9 @@ static Handle Fsync(const Arguments& args) { int fd = args[0]->Int32Value(); if (args[1]->IsFunction()) { - ASYNC_CALL(fsync, args[1], fd) + ASYNC_CALL(fsync, args[1], 0, fd) } else { - SYNC_CALL(fsync, 0, fd) + SYNC_CALL(fsync, 0, 0, fd) return Undefined(); } } @@ -602,9 +621,9 @@ static Handle Unlink(const Arguments& args) { node::Utf8Value path(args[0]); if (args[1]->IsFunction()) { - ASYNC_CALL(unlink, args[1], *path) + ASYNC_CALL(unlink, args[1], 0, *path) } else { - SYNC_CALL(unlink, *path, *path) + SYNC_CALL(unlink, *path, 0, *path) return Undefined(); } } @@ -618,9 +637,9 @@ static Handle RMDir(const Arguments& args) { node::Utf8Value path(args[0]); if (args[1]->IsFunction()) { - ASYNC_CALL(rmdir, args[1], *path) + ASYNC_CALL(rmdir, args[1], 0, *path) } else { - SYNC_CALL(rmdir, *path, *path) + SYNC_CALL(rmdir, *path, 0, *path) return Undefined(); } } @@ -636,9 +655,9 @@ static Handle MKDir(const Arguments& args) { int mode = static_cast(args[1]->Int32Value()); if (args[2]->IsFunction()) { - ASYNC_CALL(mkdir, args[2], *path, mode) + ASYNC_CALL(mkdir, args[2], 0, *path, mode) } else { - SYNC_CALL(mkdir, *path, *path, mode) + SYNC_CALL(mkdir, *path, 0, *path, mode) return Undefined(); } } @@ -652,12 +671,12 @@ static Handle ReadDir(const Arguments& args) { node::Utf8Value path(args[0]); if (args[1]->IsFunction()) { - ASYNC_CALL(readdir, args[1], *path, 0 /*flags*/) + ASYNC_CALL(readdir, args[1], 0, *path, 0 /*flags*/) } else { - SYNC_CALL(readdir, *path, *path, 0 /*flags*/) + SYNC_CALL(readdir, *path, 0, *path, 0 /*flags*/) char *namebuf = static_cast(SYNC_REQ.ptr); - int nnames = req_wrap.req.result; + int nnames = req_wrap.req.req.result; Local names = Array::New(nnames); for (int i = 0; i < nnames; i++) { @@ -692,9 +711,9 @@ static Handle Open(const Arguments& args) { int mode = static_cast(args[2]->Int32Value()); if (args[3]->IsFunction()) { - ASYNC_CALL(open, args[3], *path, flags, mode) + ASYNC_CALL(open, args[3], 0, *path, flags, mode) } else { - SYNC_CALL(open, *path, *path, flags, mode) + SYNC_CALL(open, *path, 0, *path, flags, mode) int fd = SYNC_RESULT; return scope.Close(Integer::New(fd)); } @@ -746,9 +765,9 @@ static Handle Write(const Arguments& args) { Local cb = args[5]; if (cb->IsFunction()) { - ASYNC_CALL(write, cb, fd, buf, len, pos) + ASYNC_CALL(write, cb, 0, fd, buf, len, pos) } else { - SYNC_CALL(write, 0, fd, buf, len, pos) + SYNC_CALL(write, 0, 0, fd, buf, len, pos) return scope.Close(Integer::New(SYNC_RESULT)); } } @@ -809,9 +828,9 @@ static Handle Read(const Arguments& args) { cb = args[5]; if (cb->IsFunction()) { - ASYNC_CALL(read, cb, fd, buf, len, pos); + ASYNC_CALL(read, cb, 0, fd, buf, len, pos); } else { - SYNC_CALL(read, 0, fd, buf, len, pos) + SYNC_CALL(read, 0, 0, fd, buf, len, pos) Local bytesRead = Integer::New(SYNC_RESULT); return scope.Close(bytesRead); } @@ -831,9 +850,9 @@ static Handle Chmod(const Arguments& args) { int mode = static_cast(args[1]->Int32Value()); if(args[2]->IsFunction()) { - ASYNC_CALL(chmod, args[2], *path, mode); + ASYNC_CALL(chmod, args[2], 0, *path, mode); } else { - SYNC_CALL(chmod, *path, *path, mode); + SYNC_CALL(chmod, *path, 0, *path, mode); return Undefined(); } } @@ -852,9 +871,9 @@ static Handle FChmod(const Arguments& args) { int mode = static_cast(args[1]->Int32Value()); if(args[2]->IsFunction()) { - ASYNC_CALL(fchmod, args[2], fd, mode); + ASYNC_CALL(fchmod, args[2], 0, fd, mode); } else { - SYNC_CALL(fchmod, 0, fd, mode); + SYNC_CALL(fchmod, 0, 0, fd, mode); return Undefined(); } } @@ -879,9 +898,9 @@ static Handle Chown(const Arguments& args) { uv_gid_t gid = static_cast(args[2]->Uint32Value()); if (args[3]->IsFunction()) { - ASYNC_CALL(chown, args[3], *path, uid, gid); + ASYNC_CALL(chown, args[3], 0, *path, uid, gid); } else { - SYNC_CALL(chown, *path, *path, uid, gid); + SYNC_CALL(chown, *path, 0, *path, uid, gid); return Undefined(); } } @@ -906,9 +925,9 @@ static Handle FChown(const Arguments& args) { uv_gid_t gid = static_cast(args[2]->Uint32Value()); if (args[3]->IsFunction()) { - ASYNC_CALL(fchown, args[3], fd, uid, gid); + ASYNC_CALL(fchown, args[3], 0, fd, uid, gid); } else { - SYNC_CALL(fchown, 0, fd, uid, gid); + SYNC_CALL(fchown, 0, 0, fd, uid, gid); return Undefined(); } } @@ -930,9 +949,9 @@ static Handle UTimes(const Arguments& args) { const double mtime = static_cast(args[2]->NumberValue()); if (args[3]->IsFunction()) { - ASYNC_CALL(utime, args[3], *path, atime, mtime); + ASYNC_CALL(utime, args[3], 0, *path, atime, mtime); } else { - SYNC_CALL(utime, *path, *path, atime, mtime); + SYNC_CALL(utime, *path, 0, *path, atime, mtime); return Undefined(); } } @@ -953,9 +972,9 @@ static Handle FUTimes(const Arguments& args) { const double mtime = static_cast(args[2]->NumberValue()); if (args[3]->IsFunction()) { - ASYNC_CALL(futime, args[3], fd, atime, mtime); + ASYNC_CALL(futime, args[3], 0, fd, atime, mtime); } else { - SYNC_CALL(futime, 0, fd, atime, mtime); + SYNC_CALL(futime, 0, 0, fd, atime, mtime); return Undefined(); } } diff --git a/src/node_file.h b/src/node_file.h index 5757e732b58c..a57a1238ee6a 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -27,6 +27,12 @@ namespace node { +struct node_fs_t { + uv_fs_t req; + int throwSafe; + void* data; +}; + class File { public: static void Initialize(v8::Handle target); diff --git a/test/simple/test-fs-stat-sync.js b/test/simple/test-fs-stat-sync.js new file mode 100644 index 000000000000..1c68e5e08632 --- /dev/null +++ b/test/simple/test-fs-stat-sync.js @@ -0,0 +1,168 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); +var fs = require('fs'); +var got_error = false; +var success_count = 0; + +var stats; + +// statSync +try { + stats = fs.statSync('.'); +} catch (e) { + got_error = true; +} +if (!stats) { + got_error = true; +} else { + console.dir(stats); + assert.ok(stats.mtime instanceof Date); + success_count++; +} + +try { + stats = fs.statSync('.', true); +} catch (e) { + got_error = true; +} +if (!stats) { + got_error = true; +} else { + console.dir(stats); + assert.ok(stats.mtime instanceof Date); + success_count++; +} + +var errorCaught = false; +try { + stats = fs.statSync('nonexisting_file'); +} catch (e) { + assert.ok(e instanceof Error); + success_count++; + errorCaught = true; +} +if (!errorCaught) { + got_error = true; +} + +try { + stats = fs.statSync('nonexisting_file', true); +} catch (e) { + got_error = true; +} +assert.equal(false, stats); +success_count++; + +// lstatSync +try { + stats = fs.lstatSync('.'); +} catch (e) { + got_error = true; +} +if (!stats) { + got_error = true; +} else { + console.dir(stats); + assert.ok(stats.mtime instanceof Date); + success_count++; +} + +// fstatSync +fs.open('.', 'r', undefined, function(err, fd) { + assert.ok(!err); + assert.ok(fd); + + var stats; + try { + stats = fs.fstatSync(fd); + } catch (e) { + got_error = true; + } + if (!stats) { + got_error = true; + } else { + console.dir(stats); + assert.ok(stats.mtime instanceof Date); + success_count++; + } + + assert(this === global); +}); + +// fstatSync +fs.open('.', 'r', undefined, function(err, fd) { + var stats; + try { + stats = fs.fstatSync(fd); + } catch (err) { + got_error = true; + } + if (stats) { + console.dir(stats); + assert.ok(stats.mtime instanceof Date); + success_count++; + } + fs.close(fd); +}); + +console.log('stating: ' + __filename); +try { + stats = fs.statSync(__filename); +} catch (e) { + got_error = true; +} +if (!stats) { + got_error = true; +} else { + console.dir(stats); + success_count++; + + console.log('isDirectory: ' + JSON.stringify(stats.isDirectory())); + assert.equal(false, stats.isDirectory()); + + console.log('isFile: ' + JSON.stringify(stats.isFile())); + assert.equal(true, stats.isFile()); + + console.log('isSocket: ' + JSON.stringify(stats.isSocket())); + assert.equal(false, stats.isSocket()); + + console.log('isBlockDevice: ' + JSON.stringify(stats.isBlockDevice())); + assert.equal(false, stats.isBlockDevice()); + + console.log('isCharacterDevice: ' + JSON.stringify(stats.isCharacterDevice())); + assert.equal(false, stats.isCharacterDevice()); + + console.log('isFIFO: ' + JSON.stringify(stats.isFIFO())); + assert.equal(false, stats.isFIFO()); + + console.log('isSymbolicLink: ' + JSON.stringify(stats.isSymbolicLink())); + assert.equal(false, stats.isSymbolicLink()); + + assert.ok(stats.mtime instanceof Date); +} + +process.on('exit', function() { + assert.equal(8, success_count); + assert.equal(false, got_error); +}); diff --git a/test/simple/test-fs-stat.js b/test/simple/test-fs-stat.js index 90b0ba52d4a2..3293d8ff7983 100644 --- a/test/simple/test-fs-stat.js +++ b/test/simple/test-fs-stat.js @@ -36,6 +36,34 @@ fs.stat('.', function(err, stats) { assert(this === global); }); +fs.stat('.', function(err, stats) { + if (err) { + got_error = true; + } else { + console.dir(stats); + assert.ok(stats.mtime instanceof Date); + success_count++; + } + assert(this === global); +}, true); + +fs.stat('nonexisting_file', function(err, stats) { + if (err) { + assert.ok(err instanceof Error); + success_count++; + } else { + got_error = true; + } + assert(this === global); +}); + +fs.stat('nonexisting_file', function(err, stats) { + assert.equal(true, err); + assert.equal(false, stats); + assert(this === global); + success_count++; +}, true); + fs.lstat('.', function(err, stats) { if (err) { got_error = true; @@ -84,40 +112,39 @@ fs.open('.', 'r', undefined, function(err, fd) { }); console.log('stating: ' + __filename); -fs.stat(__filename, function(err, s) { +fs.stat(__filename, function(err, stats) { if (err) { got_error = true; } else { - console.dir(s); + console.dir(stats); success_count++; - console.log('isDirectory: ' + JSON.stringify(s.isDirectory())); - assert.equal(false, s.isDirectory()); + console.log('isDirectory: ' + JSON.stringify(stats.isDirectory())); + assert.equal(false, stats.isDirectory()); - console.log('isFile: ' + JSON.stringify(s.isFile())); - assert.equal(true, s.isFile()); + console.log('isFile: ' + JSON.stringify(stats.isFile())); + assert.equal(true, stats.isFile()); - console.log('isSocket: ' + JSON.stringify(s.isSocket())); - assert.equal(false, s.isSocket()); + console.log('isSocket: ' + JSON.stringify(stats.isSocket())); + assert.equal(false, stats.isSocket()); - console.log('isBlockDevice: ' + JSON.stringify(s.isBlockDevice())); - assert.equal(false, s.isBlockDevice()); + console.log('isBlockDevice: ' + JSON.stringify(stats.isBlockDevice())); + assert.equal(false, stats.isBlockDevice()); - console.log('isCharacterDevice: ' + JSON.stringify(s.isCharacterDevice())); - assert.equal(false, s.isCharacterDevice()); + console.log('isCharacterDevice: ' + JSON.stringify(stats.isCharacterDevice())); + assert.equal(false, stats.isCharacterDevice()); - console.log('isFIFO: ' + JSON.stringify(s.isFIFO())); - assert.equal(false, s.isFIFO()); + console.log('isFIFO: ' + JSON.stringify(stats.isFIFO())); + assert.equal(false, stats.isFIFO()); - console.log('isSymbolicLink: ' + JSON.stringify(s.isSymbolicLink())); - assert.equal(false, s.isSymbolicLink()); + console.log('isSymbolicLink: ' + JSON.stringify(stats.isSymbolicLink())); + assert.equal(false, stats.isSymbolicLink()); - assert.ok(s.mtime instanceof Date); + assert.ok(stats.mtime instanceof Date); } }); process.on('exit', function() { - assert.equal(5, success_count); + assert.equal(8, success_count); assert.equal(false, got_error); }); -