class FSReqWrap: public ReqWrap<uv_fs_t> {
public:
- void* operator new(size_t size) { return new char[size]; }
- void* operator new(size_t size, char* storage) { return storage; }
+ enum Ownership { COPY, MOVE };
+
+ inline static FSReqWrap* New(Environment* env,
+ Local<Object> req,
+ const char* syscall,
+ const char* data = nullptr,
+ Ownership ownership = COPY);
+
+ inline void Dispose();
+ void ReleaseEarly() {
+ if (data_ != inline_data()) {
+ delete[] data_;
+ data_ = nullptr;
+ }
+ }
+
+ const char* syscall() const { return syscall_; }
+ const char* data() const { return data_; }
+
+ private:
FSReqWrap(Environment* env,
Local<Object> req,
const char* syscall,
- char* data = nullptr)
- : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
- syscall_(syscall),
- data_(data),
- dest_len_(0) {
+ const char* data)
+ : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP),
+ syscall_(syscall),
+ data_(data) {
Wrap(object(), this);
}
- void ReleaseEarly() {
- if (data_ == nullptr)
- return;
- delete[] data_;
- data_ = nullptr;
- }
+ ~FSReqWrap() { ReleaseEarly(); }
- inline const char* syscall() const { return syscall_; }
- inline const char* dest() const { return dest_; }
- inline unsigned int dest_len() const { return dest_len_; }
- inline void dest_len(unsigned int dest_len) { dest_len_ = dest_len; }
+ void* operator new(size_t size) = delete;
+ void* operator new(size_t size, char* storage) { return storage; }
+ char* inline_data() { return reinterpret_cast<char*>(this + 1); }
- private:
const char* syscall_;
- char* data_;
- unsigned int dest_len_;
- char dest_[1];
+ const char* data_;
+
+ DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
};
+FSReqWrap* FSReqWrap::New(Environment* env,
+ Local<Object> req,
+ const char* syscall,
+ const char* data,
+ Ownership ownership) {
+ const bool copy = (data != nullptr && ownership == COPY);
+ const size_t size = copy ? 1 + strlen(data) : 0;
+ FSReqWrap* that;
+ char* const storage = new char[sizeof(*that) + size];
+ that = new(storage) FSReqWrap(env, req, syscall, data);
+ if (copy)
+ that->data_ = static_cast<char*>(memcpy(that->inline_data(), data, size));
+ return that;
+}
+
+
+void FSReqWrap::Dispose() {
+ this->~FSReqWrap();
+ delete[] reinterpret_cast<char*>(this);
+}
+
+
static void NewFSReqWrap(const FunctionCallbackInfo<Value>& args) {
CHECK(args.IsConstructCall());
}
if (req->result < 0) {
// An error happened.
- const char* dest = req_wrap->dest_len() > 0 ? req_wrap->dest() : nullptr;
argv[0] = UVException(env->isolate(),
req->result,
req_wrap->syscall(),
nullptr,
req->path,
- dest);
+ req_wrap->data());
} else {
// error value is empty or null for non-error.
argv[0] = Null(env->isolate());
req_wrap->MakeCallback(env->oncomplete_string(), argc, argv);
uv_fs_req_cleanup(&req_wrap->req_);
- delete req_wrap;
+ req_wrap->Dispose();
}
// This struct is only used on sync fs calls.
};
-#define ASYNC_DEST_CALL(func, req, dest_path, ...) \
+#define ASYNC_DEST_CALL(func, req, dest, ...) \
Environment* env = Environment::GetCurrent(args); \
- FSReqWrap* req_wrap; \
- char* dest_str = (dest_path); \
- int dest_len = dest_str == nullptr ? 0 : strlen(dest_str); \
- char* storage = new char[sizeof(*req_wrap) + dest_len]; \
CHECK(req->IsObject()); \
- req_wrap = new(storage) FSReqWrap(env, req.As<Object>(), #func); \
- req_wrap->dest_len(dest_len); \
- if (dest_str != nullptr) { \
- memcpy(const_cast<char*>(req_wrap->dest()), \
- dest_str, \
- dest_len + 1); \
- } \
+ FSReqWrap* req_wrap = FSReqWrap::New(env, req.As<Object>(), #func, dest); \
int err = uv_fs_ ## func(env->event_loop(), \
&req_wrap->req_, \
__VA_ARGS__, \
char* buf = nullptr;
int64_t pos;
size_t len;
- bool must_free = false;
+ FSReqWrap::Ownership ownership = FSReqWrap::COPY;
// will assign buf and len if string was external
if (!StringBytes::GetExternalParts(env->isolate(),
// StorageSize may return too large a char, so correct the actual length
// by the write size
len = StringBytes::Write(env->isolate(), buf, len, args[1], enc);
- must_free = true;
+ ownership = FSReqWrap::MOVE;
}
pos = GET_OFFSET(args[2]);
req = args[4];
if (!req->IsObject()) {
SYNC_CALL(write, nullptr, fd, &uvbuf, 1, pos)
- if (must_free)
+ if (ownership == FSReqWrap::MOVE)
delete[] buf;
return args.GetReturnValue().Set(SYNC_RESULT);
}
FSReqWrap* req_wrap =
- new FSReqWrap(env, req.As<Object>(), "write", must_free ? buf : nullptr);
+ FSReqWrap::New(env, req.As<Object>(), "write", buf, ownership);
int err = uv_fs_write(env->event_loop(),
&req_wrap->req_,
fd,