From e8ce6ef790ed791b98c797a75fbccb1b88c03cf0 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 15 Apr 2009 21:23:10 +0200 Subject: [PATCH] add file open/close --- src/file.cc | 218 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/main.js | 11 ++- src/node.cc | 2 +- 3 files changed, 217 insertions(+), 14 deletions(-) diff --git a/src/file.cc b/src/file.cc index 6638f075361..e01fa71fa76 100644 --- a/src/file.cc +++ b/src/file.cc @@ -1,6 +1,11 @@ #include "node.h" #include +#include +#include +#include + + using namespace v8; class Callback { @@ -9,33 +14,32 @@ class Callback { ~Callback(); Local Call(Handle recv, int argc, Handle argv[]); private: - Persistent handle; + Persistent handle_; }; - Callback::Callback (Handle v) { HandleScope scope; Handle f = Handle::Cast(v); - handle = Persistent::New(f); + handle_ = Persistent::New(f); } Callback::~Callback () { - handle.Dispose(); - handle.Clear(); // necessary? + handle_.Dispose(); + handle_.Clear(); // necessary? } Local Callback::Call (Handle recv, int argc, Handle argv[]) { HandleScope scope; - Local r = handle->Call(recv, argc, argv); + Local r = handle_->Call(recv, argc, argv); return scope.Close(r); } static int -after_rename (eio_req *req) +AfterRename (eio_req *req) { Callback *callback = static_cast(req->data); if (callback != NULL) { @@ -65,14 +69,14 @@ JS_METHOD(rename) Callback *callback = NULL; if (!args[2]->IsUndefined()) callback = new Callback(args[2]); - eio_req *req = eio_rename(*path, *new_path, EIO_PRI_DEFAULT, after_rename, callback); + eio_req *req = eio_rename(*path, *new_path, EIO_PRI_DEFAULT, AfterRename, callback); node_eio_submit(req); return Undefined(); } static int -after_stat (eio_req *req) +AfterStat (eio_req *req) { Callback *callback = static_cast(req->data); if (callback != NULL) { @@ -134,12 +138,199 @@ JS_METHOD(stat) Callback *callback = NULL; if (!args[1]->IsUndefined()) callback = new Callback(args[1]); - eio_req *req = eio_stat(*path, EIO_PRI_DEFAULT, after_stat, callback); + eio_req *req = eio_stat(*path, EIO_PRI_DEFAULT, AfterStat, callback); node_eio_submit(req); return Undefined(); } +///////////////////// FILE ///////////////////// + +class File { +public: + File (Handle handle); + ~File (); + + static File* Unwrap (Handle obj); + + void Open (const char *path, const char *mode); + static int AfterOpen (eio_req *req); + + void Close (); + static int AfterClose (eio_req *req); + + +private: + static void MakeWeak (Persistent _, void *data); + int fd_; + Persistent handle_; +}; + +File::File (Handle handle) +{ + HandleScope scope; + fd_ = -1; + handle_ = Persistent::New(handle); + Handle external = External::New(this); + handle_->SetInternalField(0, external); + handle_.MakeWeak(this, File::MakeWeak); +} + +File::~File () +{ + Close(); + handle_->SetInternalField(0, Undefined()); + handle_.Dispose(); + handle_.Clear(); +} + +File* +File::Unwrap (Handle obj) +{ + HandleScope scope; + Handle field = Handle::Cast(obj->GetInternalField(0)); + File* file = static_cast(field->Value()); + return file; +} + +void +File::MakeWeak (Persistent _, void *data) +{ + File *file = static_cast (data); + delete file; +} + + +int +File::AfterClose (eio_req *req) +{ + File *file = static_cast(req->data); + + // TODO + printf("after close\n"); + return 0; +} + +void +File::Close () +{ + eio_req *req = eio_close (fd_, EIO_PRI_DEFAULT, File::AfterClose, this); + node_eio_submit(req); +} + +int +File::AfterOpen (eio_req *req) +{ + File *file = static_cast(req->data); + + HandleScope scope; + TryCatch try_catch; + + if(req->result < 0) { + // TODO + /* + const int argc = 2; + Local argv[argc]; + + argv[0] = Integer::New(errorno); + argv[1] = String::New(strerror(errorno)); + */ + printf("error opening file...handle me\n"); + return 0; + } + + file->fd_ = static_cast(req->result); + + file->handle_->Set(String::NewSymbol("fd"), Integer::New(req->result)); + Handle on_open_value = file->handle_->Get( String::NewSymbol("onOpen") ); + if (!on_open_value->IsFunction()) + return 0; + Handle on_open = Handle::Cast(on_open_value); + + on_open->Call(file->handle_, 0, NULL); + + if(try_catch.HasCaught()) + node_fatal_exception(try_catch); + + return 0; +} + +void +File::Open (const char *path, const char *mode) +{ + mode_t mask = umask(0x0700); + umask(mask); + + int flags = O_RDONLY; // default + // XXX is this interpretation correct? + // I don't want to to use fopen() because eio doesn't support it. + switch(mode[0]) { + case 'r': + if (mode[1] == '+') + flags = O_RDWR; + else + flags = O_RDONLY; + break; + + case 'w': + if (mode[1] == '+') + flags = O_RDWR | O_CREAT | O_TRUNC; + else + flags = O_WRONLY | O_CREAT | O_TRUNC; + break; + + case 'a': + if (mode[1] == '+') + flags = O_RDWR | O_APPEND | O_CREAT; + else + flags = O_WRONLY | O_APPEND | O_CREAT; + break; + } + + eio_req *req = eio_open (path, flags, mask, EIO_PRI_DEFAULT, File::AfterOpen, this); + node_eio_submit(req); +} + +static Handle +NewFile (const Arguments& args) +{ + HandleScope scope; + File *file = new File(args.Holder()); + if(file == NULL) + return Undefined(); // XXX raise error? + + return args.This(); +} + +JS_METHOD(file_open) +{ + if (args.Length() < 1) return Undefined(); + if (!args[0]->IsString()) return Undefined(); + + HandleScope scope; + + File *file = File::Unwrap(args.Holder()); + String::Utf8Value path(args[0]->ToString()); + if (args[1]->IsString()) { + String::AsciiValue mode(args[1]->ToString()); + file->Open(*path, *mode); + } else { + file->Open(*path, "r"); + } + + return Undefined(); +} + +JS_METHOD(file_close) +{ + HandleScope scope; + + File *file = File::Unwrap(args.Holder()); + file->Close(); + + return Undefined(); +} + void NodeInit_file (Handle target) { @@ -150,4 +341,11 @@ NodeInit_file (Handle target) JS_SET_METHOD(fs, "rename", rename); JS_SET_METHOD(fs, "stat", stat); + + Local file_template = FunctionTemplate::New(NewFile); + file_template->InstanceTemplate()->SetInternalFieldCount(1); + target->Set(String::NewSymbol("File"), file_template->GetFunction()); + + JS_SET_METHOD(file_template->InstanceTemplate(), "open", file_open); + JS_SET_METHOD(file_template->InstanceTemplate(), "close", file_close); } diff --git a/src/main.js b/src/main.js index ae847e798f4..63be09f4e85 100644 --- a/src/main.js +++ b/src/main.js @@ -42,7 +42,7 @@ function __require (path, loading_file) { // absolute path if (path.slice(0,1) === "/") { } else { - filename = node.path.join(node.path.dirname(loading_file), path); + //filename = node.path.join(node.path.dirname(loading_file), path); } node.blocking.print("require: " + filename); @@ -75,11 +75,16 @@ function __require (path, loading_file) { } // main script execution. -//__require(ARGV[1], ARGV[1]); -// +__require(ARGV[1], "."); + +/* fs.stat("/tmp/world", function (stat, status, msg) { for ( var i in stat ) { node.blocking.print(i + ": " + stat[i]); } node.blocking.print("done: " + status.toString() + " " + msg.toString()); + }); +*/ + +//var f = new File(); diff --git a/src/node.cc b/src/node.cc index 07d31b29d4a..d12512646ef 100644 --- a/src/node.cc +++ b/src/node.cc @@ -168,7 +168,7 @@ JS_METHOD(exec) static void OnFatalError (const char* location, const char* message) { - fprintf(stderr, "Fatal error. %s %s\n", location, message); + fprintf(stderr, "Fatal error: %s %s\n", location, message); ev_unloop(node_loop(), EVUNLOOP_ALL); }