Browse Source

Stat::Callback has 2 arguments for callback: current stat info and previous stat info

http://groups.google.com/group/nodejs/msg/f8e51a8e0c74bd85
v0.7.4-release
choonkeat 15 years ago
committed by Ryan Dahl
parent
commit
44d5f212fe
  1. 12
      doc/api.txt
  2. 18
      lib/posix.js
  3. 72
      src/node.cc
  4. 4
      src/node.h
  5. 69
      src/node_file.cc
  6. 5
      src/node_stat.cc
  7. 3
      test/mjsunit/test-stat-handler.js

12
doc/api.txt

@ -137,6 +137,18 @@ The second argument is optional. The +options+ if provided should be an
object containing two members a boolean, +persistent+, and +interval+, a
polling value in milliseconds. The default is +{persistent: true, interval:
0}+.
+
The +listener+ gets two arguments the current stat object and the previous
stat object:
+
-------------------------
process.watchFile(f, function (curr, prev) {
sys.puts("the current mtime is: " + curr.mtime);
sys.puts("the previous mtime was: " + prev.mtime);
});
-------------------------
+
These stat objects are instances of +posix.Stat+.
+process.unwatchFile(filename)+::
Stop watching for changes on +filename+.

18
lib/posix.js

@ -1,35 +1,37 @@
process.fs.Stats.prototype._checkModeProperty = function (property) {
process.Stats.prototype._checkModeProperty = function (property) {
return ((this.mode & property) === property);
};
process.fs.Stats.prototype.isDirectory = function () {
process.Stats.prototype.isDirectory = function () {
return this._checkModeProperty(process.S_IFDIR);
};
process.fs.Stats.prototype.isFile = function () {
process.Stats.prototype.isFile = function () {
return this._checkModeProperty(process.S_IFREG);
};
process.fs.Stats.prototype.isBlockDevice = function () {
process.Stats.prototype.isBlockDevice = function () {
return this._checkModeProperty(process.S_IFBLK);
};
process.fs.Stats.prototype.isCharacterDevice = function () {
process.Stats.prototype.isCharacterDevice = function () {
return this._checkModeProperty(process.S_IFCHR);
};
process.fs.Stats.prototype.isSymbolicLink = function () {
process.Stats.prototype.isSymbolicLink = function () {
return this._checkModeProperty(process.S_IFLNK);
};
process.fs.Stats.prototype.isFIFO = function () {
process.Stats.prototype.isFIFO = function () {
return this._checkModeProperty(process.S_IFIFO);
};
process.fs.Stats.prototype.isSocket = function () {
process.Stats.prototype.isSocket = function () {
return this._checkModeProperty(process.S_IFSOCK);
};
exports.Stats = process.Stats;
for (var key in process.fs) {
if (process.fs.hasOwnProperty(key)) exports[key] = process.fs[key];
}

72
src/node.cc

@ -160,6 +160,71 @@ ssize_t DecodeWrite(char *buf, size_t buflen,
return buflen;
}
#define DEV_SYMBOL String::NewSymbol("dev")
#define INO_SYMBOL String::NewSymbol("ino")
#define MODE_SYMBOL String::NewSymbol("mode")
#define NLINK_SYMBOL String::NewSymbol("nlink")
#define UID_SYMBOL String::NewSymbol("uid")
#define GID_SYMBOL String::NewSymbol("gid")
#define RDEV_SYMBOL String::NewSymbol("rdev")
#define SIZE_SYMBOL String::NewSymbol("size")
#define BLKSIZE_SYMBOL String::NewSymbol("blksize")
#define BLOCKS_SYMBOL String::NewSymbol("blocks")
#define ATIME_SYMBOL String::NewSymbol("atime")
#define MTIME_SYMBOL String::NewSymbol("mtime")
#define CTIME_SYMBOL String::NewSymbol("ctime")
static Persistent<FunctionTemplate> stats_constructor_template;
Local<Object> BuildStatsObject(struct stat * s) {
HandleScope scope;
Local<Object> 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);
}
// Extracts a C str from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<str conversion failed>";
@ -726,6 +791,13 @@ static Local<Object> Load(int argc, char *argv[]) {
process->Set(String::NewSymbol("EventEmitter"),
EventEmitter::constructor_template->GetFunction());
// Initialize the stats object
Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
stats_constructor_template = Persistent<FunctionTemplate>::New(stat_templ);
process->Set(String::NewSymbol("Stats"),
stats_constructor_template->GetFunction());
// Initialize the C++ modules..................filename of module
Promise::Initialize(process); // events.cc
Stdio::Initialize(process); // stdio.cc

4
src/node.h

@ -6,6 +6,8 @@
#include <eio.h>
#include <v8.h>
#include <evcom.h>
#include <sys/types.h> /* struct stat */
#include <sys/stat.h>
#include <node_object_wrap.h>
@ -51,6 +53,8 @@ ssize_t DecodeWrite(char *buf,
v8::Handle<v8::Value>,
enum encoding encoding = BINARY);
v8::Local<v8::Object> BuildStatsObject(struct stat * s);
} // namespace node
#endif // SRC_NODE_H_

69
src/node_file.cc

@ -13,20 +13,7 @@ namespace node {
using namespace v8;
#define DEV_SYMBOL String::NewSymbol("dev")
#define INO_SYMBOL String::NewSymbol("ino")
#define MODE_SYMBOL String::NewSymbol("mode")
#define NLINK_SYMBOL String::NewSymbol("nlink")
#define UID_SYMBOL String::NewSymbol("uid")
#define GID_SYMBOL String::NewSymbol("gid")
#define RDEV_SYMBOL String::NewSymbol("rdev")
#define SIZE_SYMBOL String::NewSymbol("size")
#define BLKSIZE_SYMBOL String::NewSymbol("blksize")
#define BLOCKS_SYMBOL String::NewSymbol("blocks")
#define ATIME_SYMBOL String::NewSymbol("atime")
#define MTIME_SYMBOL String::NewSymbol("mtime")
#define CTIME_SYMBOL String::NewSymbol("ctime")
#define BAD_ARGUMENTS Exception::TypeError(String::New("Bad argument"))
#define BAD_ARGUMENTS Exception::TypeError(String::New("Bad argument"))
void EIOPromise::Attach(void) {
ev_ref(EV_DEFAULT_UC);
@ -58,55 +45,6 @@ EIOPromise* EIOPromise::Create() {
return ObjectWrap::Unwrap<EIOPromise>(handle);
}
static Persistent<FunctionTemplate> stats_constructor_template;
static Local<Object> BuildStatsObject(struct stat * s) {
HandleScope scope;
Local<Object> 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) {
HandleScope scope;
@ -388,11 +326,6 @@ void File::Initialize(Handle<Object> target) {
NODE_SET_METHOD(target, "unlink", Unlink);
NODE_SET_METHOD(target, "write", Write);
Local<FunctionTemplate> t = FunctionTemplate::New();
stats_constructor_template = Persistent<FunctionTemplate>::New(t);
target->Set(String::NewSymbol("Stats"),
stats_constructor_template->GetFunction());
Local<FunctionTemplate> t2 = FunctionTemplate::New(EIOPromise::New);
EIOPromise::constructor_template = Persistent<FunctionTemplate>::New(t2);

5
src/node_stat.cc

@ -32,7 +32,10 @@ void Stat::Callback(EV_P_ ev_stat *watcher, int revents) {
Stat *handler = static_cast<Stat*>(watcher->data);
assert(watcher == &handler->watcher_);
HandleScope scope;
handler->Emit("change", 0, NULL);
Handle<Value> argv[2];
argv[0] = Handle<Value>(BuildStatsObject(&watcher->attr));
argv[1] = Handle<Value>(BuildStatsObject(&watcher->prev));
handler->Emit("change", 2, argv);
}

3
test/mjsunit/test-stat-handler.js

@ -8,9 +8,10 @@ var f2 = path.join(fixturesDir, "x2.txt");
puts("watching for changes of " + f);
var changes = 0;
process.watchFile(f, function () {
process.watchFile(f, function (curr, prev) {
puts(f + " change");
changes++;
assertTrue(curr.mtime != prev.mtime);
process.unwatchFile(f);
});

Loading…
Cancel
Save