diff --git a/src/node_file.cc b/src/node_file.cc index 4efdc06a288..5ca5416506c 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -1,5 +1,6 @@ // Copyright 2009 Ryan Dahl #include +#include #include #include @@ -84,7 +85,7 @@ static int After(eio_req *req) { argv[1] = BuildStatsObject(s); break; } - + case EIO_READLINK: { argc = 2; @@ -131,7 +132,7 @@ static int After(eio_req *req) { } } - if (req->type == EIO_WRITE) { + if (req->type == EIO_WRITE && req->int3 == 1) { assert(req->ptr2); delete [] reinterpret_cast(req->ptr2); } @@ -447,43 +448,118 @@ static Handle Open(const Arguments& args) { } } -/* node.fs.write(fd, data, position, enc, callback) - * 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 encoding - */ +// write(fd, data, position, enc, callback) +// Wrapper for write(2). +// +// 0 fd integer. file descriptor +// 1 buffer the data to write +// 2 offset where in the buffer to start from +// 3 length how much to write +// 4 position if integer, position to write at in the file. +// if null, write from the current position +// +// - OR - +// +// 0 fd integer. file descriptor +// 1 string the data to write +// 2 position if integer, position to write at in the file. +// if null, write from the current position +// 3 encoding static Handle Write(const Arguments& args) { HandleScope scope; - if (args.Length() < 4 || !args[0]->IsInt32()) { + if (!args[0]->IsInt32()) { return THROW_BAD_ARGS; } int fd = args[0]->Int32Value(); - off_t offset = args[2]->IsNumber() ? args[2]->IntegerValue() : -1; - enum encoding enc = ParseEncoding(args[3]); - ssize_t len = DecodeBytes(args[1], enc); - if (len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); + off_t pos; + ssize_t len; + char * buf; + ssize_t written; + + Local cb; + bool legacy; + + if (Buffer::HasInstance(args[1])) { + legacy = false; + // buffer + // + // 0 fd integer. file descriptor + // 1 buffer the data to write + // 2 offset where in the buffer to start from + // 3 length how much to write + // 4 position if integer, position to write at in the file. + // if null, write from the current position + + Buffer * buffer = ObjectWrap::Unwrap(args[1]->ToObject()); + + size_t off = args[2]->Int32Value(); + if (off >= buffer->length()) { + return ThrowException(Exception::Error( + String::New("Offset is out of bounds"))); + } + + len = args[3]->Int32Value(); + if (off + len > buffer->length()) { + return ThrowException(Exception::Error( + String::New("Length is extends beyond buffer"))); + } + + pos = args[4]->IsNumber() ? args[4]->IntegerValue() : -1; + + buf = (char*)buffer->data() + off; + + cb = args[5]; + + } else { + legacy = true; + // legacy interface.. args[1] is a string + + pos = args[2]->IsNumber() ? args[2]->IntegerValue() : -1; + + enum encoding enc = ParseEncoding(args[3]); + + len = DecodeBytes(args[1], enc); + if (len < 0) { + Local exception = Exception::TypeError(String::New("Bad argument")); + return ThrowException(exception); + } + + buf = new char[len]; + written = DecodeWrite(buf, len, args[1], enc); + assert(written == len); + + cb = args[4]; } - char * buf = new char[len]; - ssize_t written = DecodeWrite(buf, len, args[1], enc); - assert(written == len); + if (cb->IsFunction()) { + // WARNING: HACK AHEAD, PROCEED WITH CAUTION + // Normally here I would do + // ASYNC_CALL(write, cb, fd, buf, len, pos) + // however, I'm trying to support a legacy interface; where in the + // String version a buffer is allocated to encode into. In the After() + // function it is freed. However in the other version, we just increase + // the reference count to a buffer. We have to let After() know which + // version is being done so it can know if it needs to free 'buf' or + // not. We do that by using req->int3. + // req->int3 == 1 legacy, String version. Need to free `buf`. + // req->int3 == 0 Buffer version. Don't do anything. + eio_req *req = eio_write(fd, buf, len, pos, + EIO_PRI_DEFAULT, + After, + cb_persist(cb)); + assert(req); + req->int3 = legacy ? 1 : 0; + ev_ref(EV_DEFAULT_UC); + return Undefined(); - if (args[4]->IsFunction()) { - ASYNC_CALL(write, args[4], fd, buf, len, offset) } else { - if (offset < 0) { + if (pos < 0) { written = write(fd, buf, len); } else { - written = pwrite(fd, buf, len, offset); + written = pwrite(fd, buf, len, pos); } if (written < 0) return ThrowException(errno_exception(errno)); return scope.Close(Integer::New(written)); diff --git a/test/pummel/test-tcp-pingpong.js b/test/pummel/test-tcp-pingpong.js index 9a3266c9673..73d36c82d9d 100644 --- a/test/pummel/test-tcp-pingpong.js +++ b/test/pummel/test-tcp-pingpong.js @@ -52,6 +52,8 @@ function pingPongTest (port, host, on_complete) { }); client.addListener("data", function (data) { + puts('client got: ' + data); + assert.equal("PONG", data); count += 1;