diff --git a/doc/api.txt b/doc/api.txt index df6b8fa5cf..b48344c52a 100644 --- a/doc/api.txt +++ b/doc/api.txt @@ -437,11 +437,12 @@ node.fs.stat("/tmp/world").addCallback(function (stats) { +node.fs.stat(path)+ :: See stat(2). - - on success: Returns +stats+ object. It looks like this: + - on success: Returns +node.fs.Stats+ object. It looks like this: +{ dev: 2049, ino: 305352, mode: 16877, nlink: 12, uid: 1000, gid: 1000, rdev: 0, size: 4096, blksize: 4096, blocks: 8, atime: "2009-06-29T11:11:55Z", mtime: "2009-06-29T11:11:40Z", ctime: "2009-06-29T11:11:40Z" }+ + See the +node.fs.Stats+ section below for more information. - on error: no parameters. +node.fs.unlink(path)+ :: @@ -518,6 +519,23 @@ node.fs.cat("/etc/passwd", "utf8").addCallback(function (content) { - on success: returns +data+, what was read from the file. - on error: no parameters. +==== +node.fs.Stats+ + +Objects returned from +node.fs.stat()+ are of this type. + ++stats.isFile()+:: + ++stats.isDirectory()+:: + ++stats.isBlockDevice()+:: + ++stats.isCharacterDevice()+:: + ++stats.isSymbolicLink()+:: + ++stats.isFIFO()+:: + ++stats.isSocket()+:: === HTTP diff --git a/src/constants.cc b/src/constants.cc index 5012fc6967..2c6bb8a1b6 100644 --- a/src/constants.cc +++ b/src/constants.cc @@ -5,6 +5,8 @@ #include #include #include +#include +#include using namespace v8; using namespace node; @@ -21,6 +23,14 @@ node::DefineConstants (Handle target) NODE_DEFINE_CONSTANT(target, O_WRONLY); NODE_DEFINE_CONSTANT(target, O_RDWR); + NODE_DEFINE_CONSTANT(target, S_IFREG); + NODE_DEFINE_CONSTANT(target, S_IFDIR); + NODE_DEFINE_CONSTANT(target, S_IFCHR); + NODE_DEFINE_CONSTANT(target, S_IFBLK); + NODE_DEFINE_CONSTANT(target, S_IFIFO); + NODE_DEFINE_CONSTANT(target, S_IFLNK); + NODE_DEFINE_CONSTANT(target, S_IFSOCK); + #ifdef O_CREAT NODE_DEFINE_CONSTANT(target, O_CREAT); #endif diff --git a/src/file.cc b/src/file.cc index d278099889..aa8e64513d 100644 --- a/src/file.cc +++ b/src/file.cc @@ -58,6 +58,58 @@ EIOPromise::Create (void) return promise; } +static Persistent stats_constructor_template; + +static Local +BuildStatsObject (struct stat * s) +{ + HandleScope scope; + + Local stats = + stats_constructor_template->GetFunction()->NewInstance(); + + /* ID of device containing file */ + stats->Set(DEV_SYMBOL, Integer::New(s->st_dev)); + + /* inode number */ + stats->Set(INO_SYMBOL, Integer::New(s->st_ino)); + + /* protection */ + stats->Set(MODE_SYMBOL, Integer::New(s->st_mode)); + + /* number of hard links */ + stats->Set(NLINK_SYMBOL, Integer::New(s->st_nlink)); + + /* user ID of owner */ + stats->Set(UID_SYMBOL, Integer::New(s->st_uid)); + + /* group ID of owner */ + stats->Set(GID_SYMBOL, Integer::New(s->st_gid)); + + /* device ID (if special file) */ + stats->Set(RDEV_SYMBOL, Integer::New(s->st_rdev)); + + /* total size, in bytes */ + stats->Set(SIZE_SYMBOL, Integer::New(s->st_size)); + + /* blocksize for filesystem I/O */ + stats->Set(BLKSIZE_SYMBOL, Integer::New(s->st_blksize)); + + /* number of blocks allocated */ + stats->Set(BLOCKS_SYMBOL, Integer::New(s->st_blocks)); + + /* time of last access */ + stats->Set(ATIME_SYMBOL, NODE_UNIXTIME_V8(s->st_atime)); + + /* time of last modification */ + stats->Set(MTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_mtime)); + + /* time of last status change */ + stats->Set(CTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_ctime)); + + return scope.Close(stats); +} + int EIOPromise::After (eio_req *req) { @@ -93,23 +145,9 @@ EIOPromise::After (eio_req *req) case EIO_STAT: { - Local stats = Object::New(); struct stat *s = reinterpret_cast(req->ptr2); - stats->Set(DEV_SYMBOL, Integer::New(s->st_dev)); /* ID of device containing file */ - stats->Set(INO_SYMBOL, Integer::New(s->st_ino)); /* inode number */ - stats->Set(MODE_SYMBOL, Integer::New(s->st_mode)); /* protection */ - stats->Set(NLINK_SYMBOL, Integer::New(s->st_nlink)); /* number of hard links */ - stats->Set(UID_SYMBOL, Integer::New(s->st_uid)); /* user ID of owner */ - stats->Set(GID_SYMBOL, Integer::New(s->st_gid)); /* group ID of owner */ - stats->Set(RDEV_SYMBOL, Integer::New(s->st_rdev)); /* device ID (if special file) */ - stats->Set(SIZE_SYMBOL, Integer::New(s->st_size)); /* total size, in bytes */ - stats->Set(BLKSIZE_SYMBOL, Integer::New(s->st_blksize)); /* blocksize for filesystem I/O */ - stats->Set(BLOCKS_SYMBOL, Integer::New(s->st_blocks)); /* number of blocks allocated */ - stats->Set(ATIME_SYMBOL, NODE_UNIXTIME_V8(s->st_atime)); /* time of last access */ - stats->Set(MTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_mtime)); /* time of last modification */ - stats->Set(CTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_ctime)); /* time of last status change */ argc = 1; - argv[0] = stats; + argv[0] = BuildStatsObject(s); break; } @@ -350,4 +388,9 @@ File::Initialize (Handle target) NODE_SET_METHOD(target, "stat", Stat); NODE_SET_METHOD(target, "unlink", Unlink); NODE_SET_METHOD(target, "write", Write); + + Local t = FunctionTemplate::New(); + stats_constructor_template = Persistent::New(t); + target->Set(String::NewSymbol("Stats"), + stats_constructor_template->GetFunction()); } diff --git a/src/file.js b/src/file.js index 3f586545ae..84b042a6a3 100644 --- a/src/file.js +++ b/src/file.js @@ -39,3 +39,35 @@ node.fs.cat = function (path, encoding) { }); return cat_promise; }; + +node.fs.Stats.prototype._checkModeProperty = function (property) { + return ((this.mode & property) == property); +}; + +node.fs.Stats.prototype.isDirectory = function () { + return this._checkModeProperty(node.S_IFDIR); +}; + +node.fs.Stats.prototype.isFile = function () { + return this._checkModeProperty(node.S_IFREG); +}; + +node.fs.Stats.prototype.isBlockDevice = function () { + return this._checkModeProperty(node.S_IFBLK); +}; + +node.fs.Stats.prototype.isCharacterDevice = function () { + return this._checkModeProperty(node.S_IFCHR); +}; + +node.fs.Stats.prototype.isSymbolicLink = function () { + return this._checkModeProperty(node.S_IFLNK); +}; + +node.fs.Stats.prototype.isFIFO = function () { + return this._checkModeProperty(node.S_IFIFO); +}; + +node.fs.Stats.prototype.isSocket = function () { + return this._checkModeProperty(node.S_IFSOCK); +}; diff --git a/test/mjsunit/test-fs-stat.js b/test/mjsunit/test-fs-stat.js index 72c7d62e6e..7867e2d497 100644 --- a/test/mjsunit/test-fs-stat.js +++ b/test/mjsunit/test-fs-stat.js @@ -1,7 +1,7 @@ include("mjsunit.js"); var got_error = false; -var got_success = false; +var success_count = 0; var stats; var promise = node.fs.stat("."); @@ -9,15 +9,45 @@ var promise = node.fs.stat("."); promise.addCallback(function (_stats) { stats = _stats; p(stats); - got_success = true; + success_count++; }); promise.addErrback(function () { got_error = true; }); +puts("stating: " + __filename); +node.fs.stat(__filename).addCallback(function (s) { + p(s); + success_count++; + + puts("isDirectory: " + JSON.stringify( s.isDirectory() ) ); + assertFalse(s.isDirectory()); + + puts("isFile: " + JSON.stringify( s.isFile() ) ); + assertTrue(s.isFile()); + + puts("isSocket: " + JSON.stringify( s.isSocket() ) ); + assertFalse(s.isSocket()); + + puts("isBlockDevice: " + JSON.stringify( s.isBlockDevice() ) ); + assertFalse(s.isBlockDevice()); + + puts("isCharacterDevice: " + JSON.stringify( s.isCharacterDevice() ) ); + assertFalse(s.isCharacterDevice()); + + puts("isFIFO: " + JSON.stringify( s.isFIFO() ) ); + assertFalse(s.isFIFO()); + + puts("isSymbolicLink: " + JSON.stringify( s.isSymbolicLink() ) ); + assertFalse(s.isSymbolicLink()); +}).addErrback(function () { + got_error = true; +}); + + process.addListener("exit", function () { - assertTrue(got_success); + assertEquals(2, success_count); assertFalse(got_error); assertTrue(stats.mtime instanceof Date); });