Clean up eio wrappers. Create EIOPromise.
authorRyan <ry@tinyclouds.org>
Tue, 25 Aug 2009 00:29:45 +0000 (02:29 +0200)
committerRyan <ry@tinyclouds.org>
Thu, 3 Sep 2009 19:32:21 +0000 (21:32 +0200)
src/events.cc
src/events.h
src/file.cc
src/file.h

index c1af9b6..8d00d24 100644 (file)
@@ -220,29 +220,9 @@ Promise::Detach (void)
     coroutine_top->Destack();
   }
 
-  if (ref_) {
-    ev_unref(EV_DEFAULT_UC);
-  }
-
   ObjectWrap::Detach();
 }
 
-Promise*
-Promise::Create (bool ref)
-{
-  HandleScope scope;
-
-  Local<Object> handle =
-    Promise::constructor_template->GetFunction()->NewInstance();
-
-  Promise *promise = ObjectWrap::Unwrap<Promise>(handle);
-
-  promise->ref_ = ref;
-  if (ref) ev_ref(EV_DEFAULT_UC);
-
-  return promise;
-}
-
 bool
 Promise::EmitSuccess (int argc, v8::Handle<v8::Value> argv[])
 {
@@ -262,3 +242,18 @@ Promise::EmitError (int argc, v8::Handle<v8::Value> argv[])
 
   return r;
 }
+
+Promise*
+Promise::Create (void)
+{
+  HandleScope scope;
+
+  Local<Object> handle =
+    Promise::constructor_template->GetFunction()->NewInstance();
+
+  Promise *promise = new Promise();
+  promise->Wrap(handle);
+  promise->Attach();
+
+  return promise;
+}
index 91a8f80..0e44c8f 100644 (file)
@@ -23,14 +23,12 @@ class Promise : public EventEmitter {
  public:
   static void Initialize (v8::Handle<v8::Object> target);
   static v8::Persistent<v8::FunctionTemplate> constructor_template;
-
-  static Promise* Create (bool ref = false);
+  static Promise* Create (void);
 
   bool EmitSuccess (int argc, v8::Handle<v8::Value> argv[]);
   bool EmitError (int argc, v8::Handle<v8::Value> argv[]);
   void Block ();
 
-
   v8::Handle<v8::Object> Handle ()
   {
     return handle_;
@@ -45,7 +43,6 @@ class Promise : public EventEmitter {
   virtual void Detach (void);
 
   bool blocking_;
-  bool ref_;
   Promise *prev_; /* for the prev in the Poor Man's coroutine stack */
 
   void Destack ();
@@ -53,10 +50,8 @@ class Promise : public EventEmitter {
   Promise () : EventEmitter()
   {
     blocking_ = false;
-    ref_ = false;
     prev_ = NULL;
   }
 };
-
 } // namespace node
 #endif
index 6528fae..a79e59d 100644 (file)
@@ -28,184 +28,242 @@ using namespace node;
 #define CTIME_SYMBOL       String::NewSymbol("ctime")
 #define BAD_ARGUMENTS      Exception::TypeError(String::New("Bad argument"))
 
-static int
-AfterClose (eio_req *req)
+void
+EIOPromise::Attach (void)
 {
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-  if (req->result == 0) {
-    promise->EmitSuccess(0, NULL);
-  } else {
-    promise->EmitError(0, NULL);
-  }
-  return 0;
+  ev_ref(EV_DEFAULT_UC);
+  Promise::Attach();
 }
 
-static Handle<Value>
-Close (const Arguments& args)
+void
+EIOPromise::Detach (void)
+{
+  Promise::Detach();
+  ev_unref(EV_DEFAULT_UC);
+}
+
+EIOPromise*
+EIOPromise::Create (void)
 {
-  if (args.Length() < 1 || !args[0]->IsInt32())
-    return ThrowException(BAD_ARGUMENTS);
   HandleScope scope;
-  int fd = args[0]->Int32Value();
 
-  Promise *promise = Promise::Create(true);
+  Local<Object> handle =
+    Promise::constructor_template->GetFunction()->NewInstance();
 
-  eio_close(fd, EIO_PRI_DEFAULT, AfterClose, promise);
-  return scope.Close(promise->Handle());
+  EIOPromise *promise = new EIOPromise();
+  promise->Wrap(handle);
+
+  promise->Attach();
+
+  return promise;
 }
 
-static int
-AfterRename (eio_req *req)
+#define NODE_UNIXTIME(t) v8::Date::New(1000*static_cast<double>(t))
+int
+EIOPromise::After (eio_req *req)
 {
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-  if (req->result == 0) {
-    promise->EmitSuccess(0, NULL);
-  } else {
-    promise->EmitError(0, NULL);
+  HandleScope scope;
+
+  EIOPromise *promise = reinterpret_cast<EIOPromise*>(req->data);
+  assert(req == promise->req_);
+
+  if (req->errorno != 0) {
+    Local<Value> exception = Exception::Error(
+        String::NewSymbol(strerror(req->errorno)));
+    promise->EmitError(1, &exception);
+    return 0;
+  }
+
+  int argc = 0;
+  Local<Value> argv[5];  // 5 is the maximum number of args
+
+  switch (req->type) {
+    case EIO_CLOSE:
+    case EIO_RENAME:
+    case EIO_UNLINK:
+    case EIO_RMDIR:
+      argc = 0;
+      break;
+
+    case EIO_OPEN:
+    case EIO_WRITE:
+      argc = 1;
+      argv[0] = Integer::New(req->result);
+      break;
+
+    case EIO_STAT:
+    {
+      Local<Object> stats = Object::New();
+      struct stat *s = reinterpret_cast<struct stat*>(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(s->st_atime)); /* time of last access */
+      stats->Set(MTIME_SYMBOL, NODE_UNIXTIME(s->st_mtime)); /* time of last modification */
+      stats->Set(CTIME_SYMBOL, NODE_UNIXTIME(s->st_ctime)); /* time of last status change */
+      argc = 1;
+      argv[0] = stats;
+      break;
+    }
+
+    case EIO_READ:
+    {
+      argc = 2;
+      // FIXME the following is really ugly!
+      if (promise->encoding_ == RAW) {
+        if (req->result == 0) {
+          argv[0] = Local<Value>::New(Null());
+          argv[1] = Integer::New(0);
+        } else {
+          char *buf = reinterpret_cast<char*>(req->ptr2);
+          size_t len = req->result;
+          Local<Array> array = Array::New(len);
+          for (unsigned int i = 0; i < len; i++) {
+            unsigned char val = reinterpret_cast<const unsigned char*>(buf)[i];
+            array->Set(Integer::New(i), Integer::New(val));
+          }
+          argv[0] = array;
+          argv[1] = Integer::New(req->result);
+        }
+      } else {
+        // UTF8
+        if (req->result == 0) {
+          // eof
+          argv[0] = Local<Value>::New(Null());
+          argv[1] = Integer::New(0);
+        } else {
+          char *buf = reinterpret_cast<char*>(req->ptr2);
+          argv[0] = String::New(buf, req->result);
+          argv[1] = Integer::New(req->result);
+        }
+      }
+      break;
+    }
+
+    default:
+      assert(0 && "Unhandled eio response");
   }
+
+  promise->EmitSuccess(argc, argv);
+
   return 0;
 }
 
-static Handle<Value> Rename (const Arguments& args)
+static Handle<Value>
+Close (const Arguments& args)
 {
-  if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString())
-    return ThrowException(BAD_ARGUMENTS);
   HandleScope scope;
-  String::Utf8Value path(args[0]->ToString());
-  String::Utf8Value new_path(args[1]->ToString());
 
-  Promise *promise = Promise::Create(true);
+  if (args.Length() < 1 || !args[0]->IsInt32()) {
+    return ThrowException(BAD_ARGUMENTS);
+  }
 
-  eio_rename(*path, *new_path, EIO_PRI_DEFAULT, AfterRename, promise);
-  return scope.Close(promise->Handle());
+  int fd = args[0]->Int32Value();
+
+  return scope.Close(EIOPromise::Close(fd));
 }
 
-static int
-AfterUnlink (eio_req *req)
+static Handle<Value>
+Stat (const Arguments& args)
 {
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-  if (req->result == 0) {
-    promise->EmitSuccess(0, NULL);
-  } else {
-    promise->EmitError(0, NULL);
+  HandleScope scope;
+
+  if (args.Length() < 1 || !args[0]->IsString()) {
+    return ThrowException(BAD_ARGUMENTS);
   }
-  return 0;
+
+  String::Utf8Value path(args[0]->ToString());
+
+  return scope.Close(EIOPromise::Stat(*path));
 }
 
-static Handle<Value> Unlink (const Arguments& args)
+static Handle<Value>
+Rename (const Arguments& args)
 {
-  if (args.Length() < 1 || !args[0]->IsString())
-    return ThrowException(BAD_ARGUMENTS);
   HandleScope scope;
+
+  if (args.Length() < 2 || !args[0]->IsString() || !args[1]->IsString()) {
+    return ThrowException(BAD_ARGUMENTS);
+  }
+
   String::Utf8Value path(args[0]->ToString());
-  Promise *promise = Promise::Create(true);
-  eio_unlink(*path, EIO_PRI_DEFAULT, AfterUnlink, promise);
+  String::Utf8Value new_path(args[1]->ToString());
+
+  return scope.Close(EIOPromise::Rename(*path, *new_path));
+  Promise *promise = EIOPromise::Create();
+
   return scope.Close(promise->Handle());
 }
 
-static int
-AfterRMDir (eio_req *req)
+static Handle<Value> Unlink (const Arguments& args)
 {
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-  if (req->result == 0) {
-    promise->EmitSuccess(0, NULL);
-  } else {
-    promise->EmitError(0, NULL);
-  }
-  return 0;
-}
+  HandleScope scope;
 
-static Handle<Value> RMDir (const Arguments& args)
-{
-  if (args.Length() < 1 || !args[0]->IsString())
+  if (args.Length() < 1 || !args[0]->IsString()) {
     return ThrowException(BAD_ARGUMENTS);
-  HandleScope scope;
+  }
+
   String::Utf8Value path(args[0]->ToString());
-  Promise *promise = Promise::Create(true);
-  eio_rmdir(*path, EIO_PRI_DEFAULT, AfterRMDir, promise);
-  return scope.Close(promise->Handle());
+  return scope.Close(EIOPromise::Unlink(*path));
 }
 
-static int
-AfterOpen (eio_req *req)
+static Handle<Value>
+RMDir (const Arguments& args)
 {
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
+  HandleScope scope;
 
-  if (req->result < 0) {
-    promise->EmitError(0, NULL);
-    return 0;
+  if (args.Length() < 1 || !args[0]->IsString()) {
+    return ThrowException(BAD_ARGUMENTS);
   }
 
-  HandleScope scope;
-  Local<Value> argv[1] = { Integer::New(req->result) };
-  promise->EmitSuccess(1, argv);
-  return 0;
+  String::Utf8Value path(args[0]->ToString());
+  return scope.Close(EIOPromise::RMDir(*path));
 }
 
 static Handle<Value>
 Open (const Arguments& args)
 {
+  HandleScope scope;
+
   if ( args.Length() < 3
     || !args[0]->IsString()
     || !args[1]->IsInt32()
     || !args[2]->IsInt32()
      ) return ThrowException(BAD_ARGUMENTS);
 
-  HandleScope scope;
   String::Utf8Value path(args[0]->ToString());
   int flags = args[1]->Int32Value();
   mode_t mode = static_cast<mode_t>(args[2]->Int32Value());
 
-  Promise *promise = Promise::Create(true);
-
-  eio_open(*path, flags, mode, EIO_PRI_DEFAULT, AfterOpen, promise);
-  return scope.Close(promise->Handle());
-}
-
-static int
-AfterWrite (eio_req *req)
-{
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-
-  if (req->result < 0) {
-    promise->EmitError(0, NULL);
-    return 0;
-  }
-
-  HandleScope scope;
-
-  free(req->ptr2);
-
-  ssize_t written = req->result;
-  Local<Value> argv[1];
-  argv[0] = written >= 0 ? Integer::New(written) : Integer::New(0);
-
-  promise->EmitSuccess(1, argv);
-  return 0;
+  return scope.Close(EIOPromise::Open(*path, flags, mode));
 }
 
-
-/* node.fs.write(fd, data, position, callback)
+/* node.fs.write(fd, data, position=null)
  * Wrapper for write(2).
  *
  * 0 fd        integer. file descriptor
  * 1 data      the data to write (string = utf8, array = raw)
  * 2 position  if integer, position to write at in the file.
  *             if null, write from the current position
- *
- * 3 callback(errorno, written)
  */
 static Handle<Value>
 Write (const Arguments& args)
 {
-  if ( args.Length() < 3
-    || !args[0]->IsInt32()
-     ) return ThrowException(BAD_ARGUMENTS);
-
   HandleScope scope;
 
+  if (args.Length() < 2 || !args[0]->IsInt32()) {
+    return ThrowException(BAD_ARGUMENTS);
+  }
+
   int fd = args[0]->Int32Value();
-  off_t pos = args[2]->IsNumber() ? args[2]->IntegerValue() : -1;
+  off_t offset = args[2]->IsNumber() ? args[2]->IntegerValue() : -1;
 
   char *buf = NULL;
   size_t len = 0;
@@ -231,92 +289,27 @@ Write (const Arguments& args)
     return ThrowException(BAD_ARGUMENTS);
   }
 
-  Promise *promise = Promise::Create(true);
-  eio_write(fd, buf, len, pos, EIO_PRI_DEFAULT, AfterWrite, promise);
-  return scope.Close(promise->Handle());
-}
-
-static int
-AfterUtf8Read (eio_req *req)
-{
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-
-  if (req->result < 0) {
-    promise->EmitError(0, NULL);
-    return 0;
-  }
-
-  HandleScope scope;
-
-  Local<Value> argv[2];
-
-  if (req->result == 0) {
-    // eof
-    argv[0] = Local<Value>::New(Null());
-    argv[1] = Integer::New(0);
-  } else {
-    char *buf = reinterpret_cast<char*>(req->ptr2);
-    argv[0] = String::New(buf, req->result);
-    argv[1] = Integer::New(req->result);
-  }
-
-  promise->EmitSuccess(2, argv);
-  return 0;
-}
-
-static int
-AfterRawRead(eio_req *req)
-{
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-
-  if (req->result < 0) {
-    promise->EmitError(0, NULL);
-    return 0;
-  }
-
-  HandleScope scope;
-  Local<Value> argv[2];
-
-  if (req->result == 0) {
-    argv[0] = Local<Value>::New(Null());
-    argv[1] = Integer::New(0);
-  } else {
-    char *buf = reinterpret_cast<char*>(req->ptr2);
-    size_t len = req->result;
-    Local<Array> array = Array::New(len);
-    for (unsigned int i = 0; i < len; i++) {
-      unsigned char val = reinterpret_cast<const unsigned char*>(buf)[i];
-      array->Set(Integer::New(i), Integer::New(val));
-    }
-    argv[0] = array;
-    argv[1] = Integer::New(req->result);
-  }
-
-  promise->EmitSuccess(2, argv);
-  return 0;
+  return scope.Close(EIOPromise::Write(fd, buf, len, offset));
 }
 
-/* node.fs.read(fd, length, position, encoding, callback)
+/* node.fs.read(fd, length, position, encoding)
  * Wrapper for read(2).
  *
  * 0 fd        integer. file descriptor
  * 1 length    integer. length to read
  * 2 position  if integer, position to read from in the file.
  *             if null, read from the current position
- * 3 encoding  either node.fs.UTF8 or node.fs.RAW
- *
- * 4 callback(errorno, data)
+ * 3 encoding  either node.UTF8 or node.RAW
  */
 static Handle<Value>
 Read (const Arguments& args)
 {
-  if ( args.Length() < 2
-    || !args[0]->IsInt32()   // fd
-    || !args[1]->IsNumber()  // len
-     ) return ThrowException(BAD_ARGUMENTS);
-
   HandleScope scope;
 
+  if (args.Length() < 2 || !args[0]->IsInt32() || !args[1]->IsNumber()) {
+    return ThrowException(BAD_ARGUMENTS);
+  }
+
   int fd = args[0]->Int32Value();
   size_t len = args[1]->IntegerValue();
   off_t pos = args[2]->IsNumber() ? args[2]->IntegerValue() : -1;
@@ -326,94 +319,7 @@ Read (const Arguments& args)
     encoding = static_cast<enum encoding>(args[3]->Int32Value());
   }
 
-  Promise *promise = Promise::Create(true);
-
-  // NOTE: 2nd param: NULL pointer tells eio to allocate it itself
-  eio_read(fd, NULL, len, pos, EIO_PRI_DEFAULT,
-      encoding == UTF8 ? AfterUtf8Read : AfterRawRead, promise);
-
-  return scope.Close(promise->Handle());
-}
-
-static int
-AfterStat (eio_req *req)
-{
-  Promise *promise = reinterpret_cast<Promise*>(req->data);
-
-  if (req->result < 0) {
-    promise->EmitError(0, NULL);
-    return 0;
-  }
-
-  HandleScope scope;
-
-  Local<Object> stats = Object::New();
-
-  struct stat *s = reinterpret_cast<struct stat*>(req->ptr2);
-
-  /* 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, Date::New(1000*static_cast<double>(s->st_atime)));
-  /* time of last modification */
-  stats->Set(MTIME_SYMBOL, Date::New(1000*static_cast<double>(s->st_mtime)));
-  /* time of last status change */
-  stats->Set(CTIME_SYMBOL, Date::New(1000*static_cast<double>(s->st_ctime)));
-
-  Local<Value> argv[1] = { stats };
-  promise->EmitSuccess(1, argv);
-
-  return 0;
-}
-
-static Handle<Value>
-Stat (const Arguments& args)
-{
-  if (args.Length() < 1 || !args[0]->IsString())
-    return ThrowException(BAD_ARGUMENTS);
-
-  HandleScope scope;
-
-  String::Utf8Value path(args[0]->ToString());
-
-  Promise *promise = Promise::Create(true);
-
-  eio_stat(*path, EIO_PRI_DEFAULT, AfterStat, promise);
-
-  return scope.Close(promise->Handle());
-}
-
-static Handle<Value>
-StrError (const Arguments& args)
-{
-  if (args.Length() < 1) return v8::Undefined();
-  if (!args[0]->IsNumber()) return v8::Undefined();
-
-  HandleScope scope;
-
-  int errorno = args[0]->IntegerValue();
-
-  Local<String> message = String::New(strerror(errorno));
-
-  return scope.Close(message);
+  return scope.Close(EIOPromise::Read(fd, len, pos, encoding));
 }
 
 void
@@ -421,7 +327,6 @@ File::Initialize (Handle<Object> target)
 {
   HandleScope scope;
 
-  // POSIX Wrappers
   NODE_SET_METHOD(target, "close", Close);
   NODE_SET_METHOD(target, "open", Open);
   NODE_SET_METHOD(target, "read", Read);
@@ -430,6 +335,4 @@ File::Initialize (Handle<Object> target)
   NODE_SET_METHOD(target, "stat", Stat);
   NODE_SET_METHOD(target, "unlink", Unlink);
   NODE_SET_METHOD(target, "write", Write);
-
-  NODE_SET_METHOD(target, "strerror",  StrError);
 }
index e48694c..02da720 100644 (file)
 #ifndef node_file_h
 #define node_file_h
 
+#include "node.h"
+#include "events.h"
 #include <v8.h>
 
 namespace node {
 
+/* Are you missing your favorite POSIX function? It might be very easy to
+ * add a wrapper. Take a look in deps/libeio/eio.h at the list of wrapper
+ * functions.  If your function is in that list, just follow the lead of
+ * EIOPromise::Open. You'll need to add two functions, one static function
+ * in EIOPromise, and one static function which interprets the javascript
+ * args in src/file.cc. Then just a reference to that function in
+ * File::Initialize() and you should be good to go.
+ * Don't forget to add a test to test/mjsunit.
+ */
+
+#define NODE_V8_METHOD_DECLARE(name) \
+  static v8::Handle<v8::Value> name (const v8::Arguments& args)
+
 class File {
 public:
   static void Initialize (v8::Handle<v8::Object> target);
 };
 
+class EIOPromise : public Promise {
+ public:
+  static v8::Handle<v8::Object>
+  Open (const char *path, int flags, mode_t mode)
+  {
+    EIOPromise *p = Create();
+    p->req_ = eio_open(path, flags, mode, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static v8::Handle<v8::Object>
+  Close (int fd)
+  {
+    EIOPromise *p = Create();
+    p->req_ = eio_close(fd, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static v8::Handle<v8::Object>
+  Write (int fd, void *buf, size_t count, off_t offset)
+  {
+    EIOPromise *p = Create();
+    p->req_ = eio_write(fd, buf, count, offset, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static v8::Handle<v8::Object>
+  Read (int fd, size_t count, off_t offset, enum encoding encoding)
+  {
+    EIOPromise *p = Create();
+    p->encoding_ = encoding;
+    // NOTE: 2nd param: NULL pointer tells eio to allocate it itself
+    p->req_ = eio_read(fd, NULL, count, offset, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static v8::Handle<v8::Object>
+  Stat (const char *path)
+  {
+    EIOPromise *p = Create();
+    p->req_ = eio_stat(path, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static v8::Handle<v8::Object>
+  Rename (const char *path, const char *new_path)
+  {
+    EIOPromise *p = Create();
+    p->req_ = eio_rename(path, new_path, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static v8::Handle<v8::Object>
+  Unlink (const char *path)
+  {
+    EIOPromise *p = Create();
+    p->req_ = eio_unlink(path, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static v8::Handle<v8::Object>
+  RMDir (const char *path)
+  {
+    EIOPromise *p = Create();
+    p->req_ = eio_rmdir(path, EIO_PRI_DEFAULT, After, p);
+    return p->handle_;
+  }
+
+  static EIOPromise* Create (void);
+
+ protected:
+
+  void Attach (void);
+  void Detach (void);
+
+  EIOPromise () : Promise() { }
+
+ private:
+
+  static int After (eio_req *req);
+
+  eio_req *req_;
+  enum encoding encoding_;
+};
+
 } // namespace node
 #endif // node_file_h