|
|
@ -1,6 +1,11 @@ |
|
|
|
#include "node.h" |
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/stat.h> |
|
|
|
#include <fcntl.h> |
|
|
|
|
|
|
|
|
|
|
|
using namespace v8; |
|
|
|
|
|
|
|
class Callback { |
|
|
@ -9,33 +14,32 @@ class Callback { |
|
|
|
~Callback(); |
|
|
|
Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]); |
|
|
|
private: |
|
|
|
Persistent<Function> handle; |
|
|
|
Persistent<Function> handle_; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Callback::Callback (Handle<Value> v) |
|
|
|
{ |
|
|
|
HandleScope scope; |
|
|
|
Handle<Function> f = Handle<Function>::Cast(v); |
|
|
|
handle = Persistent<Function>::New(f); |
|
|
|
handle_ = Persistent<Function>::New(f); |
|
|
|
} |
|
|
|
|
|
|
|
Callback::~Callback () |
|
|
|
{ |
|
|
|
handle.Dispose(); |
|
|
|
handle.Clear(); // necessary?
|
|
|
|
handle_.Dispose(); |
|
|
|
handle_.Clear(); // necessary?
|
|
|
|
} |
|
|
|
|
|
|
|
Local<Value> |
|
|
|
Callback::Call (Handle<Object> recv, int argc, Handle<Value> argv[]) |
|
|
|
{ |
|
|
|
HandleScope scope; |
|
|
|
Local<Value> r = handle->Call(recv, argc, argv); |
|
|
|
Local<Value> 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<Callback*>(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<Callback*>(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<Object> handle); |
|
|
|
~File (); |
|
|
|
|
|
|
|
static File* Unwrap (Handle<Object> 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<Value> _, void *data); |
|
|
|
int fd_; |
|
|
|
Persistent<Object> handle_; |
|
|
|
}; |
|
|
|
|
|
|
|
File::File (Handle<Object> handle) |
|
|
|
{ |
|
|
|
HandleScope scope; |
|
|
|
fd_ = -1; |
|
|
|
handle_ = Persistent<Object>::New(handle); |
|
|
|
Handle<External> 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<Object> obj) |
|
|
|
{ |
|
|
|
HandleScope scope; |
|
|
|
Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0)); |
|
|
|
File* file = static_cast<File*>(field->Value()); |
|
|
|
return file; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
File::MakeWeak (Persistent<Value> _, void *data) |
|
|
|
{ |
|
|
|
File *file = static_cast<File*> (data); |
|
|
|
delete file; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
File::AfterClose (eio_req *req) |
|
|
|
{ |
|
|
|
File *file = static_cast<File*>(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<File*>(req->data); |
|
|
|
|
|
|
|
HandleScope scope; |
|
|
|
TryCatch try_catch; |
|
|
|
|
|
|
|
if(req->result < 0) { |
|
|
|
// TODO
|
|
|
|
/*
|
|
|
|
const int argc = 2; |
|
|
|
Local<Value> 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<int>(req->result); |
|
|
|
|
|
|
|
file->handle_->Set(String::NewSymbol("fd"), Integer::New(req->result)); |
|
|
|
Handle<Value> on_open_value = file->handle_->Get( String::NewSymbol("onOpen") ); |
|
|
|
if (!on_open_value->IsFunction()) |
|
|
|
return 0; |
|
|
|
Handle<Function> on_open = Handle<Function>::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<Value> |
|
|
|
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<Object> target) |
|
|
|
{ |
|
|
@ -150,4 +341,11 @@ NodeInit_file (Handle<Object> target) |
|
|
|
|
|
|
|
JS_SET_METHOD(fs, "rename", rename); |
|
|
|
JS_SET_METHOD(fs, "stat", stat); |
|
|
|
|
|
|
|
Local<FunctionTemplate> 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); |
|
|
|
} |
|
|
|