|
|
|
// Copyright Joyent, Inc. and other Node contributors.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
// copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
|
|
// following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
#include "async-wrap.h"
|
|
|
|
#include "async-wrap-inl.h"
|
|
|
|
#include "env.h"
|
|
|
|
#include "env-inl.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "util-inl.h"
|
|
|
|
#include "node.h"
|
|
|
|
#include "handle_wrap.h"
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
9 years ago
|
|
|
#include "string_bytes.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
namespace node {
|
|
|
|
|
|
|
|
using v8::Context;
|
|
|
|
using v8::FunctionCallbackInfo;
|
|
|
|
using v8::FunctionTemplate;
|
|
|
|
using v8::HandleScope;
|
|
|
|
using v8::Integer;
|
|
|
|
using v8::Local;
|
|
|
|
using v8::MaybeLocal;
|
|
|
|
using v8::Object;
|
|
|
|
using v8::String;
|
|
|
|
using v8::Value;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
class FSEventWrap: public HandleWrap {
|
|
|
|
public:
|
|
|
|
static void Initialize(Local<Object> target,
|
|
|
|
Local<Value> unused,
|
|
|
|
Local<Context> context);
|
|
|
|
static void New(const FunctionCallbackInfo<Value>& args);
|
|
|
|
static void Start(const FunctionCallbackInfo<Value>& args);
|
|
|
|
static void Close(const FunctionCallbackInfo<Value>& args);
|
|
|
|
|
|
|
|
size_t self_size() const override { return sizeof(*this); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
static const encoding kDefaultEncoding = UTF8;
|
|
|
|
|
|
|
|
FSEventWrap(Environment* env, Local<Object> object);
|
|
|
|
~FSEventWrap() override;
|
|
|
|
|
|
|
|
static void OnEvent(uv_fs_event_t* handle, const char* filename, int events,
|
|
|
|
int status);
|
|
|
|
|
|
|
|
uv_fs_event_t handle_;
|
|
|
|
bool initialized_ = false;
|
|
|
|
enum encoding encoding_ = kDefaultEncoding;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
FSEventWrap::FSEventWrap(Environment* env, Local<Object> object)
|
|
|
|
: HandleWrap(env,
|
|
|
|
object,
|
|
|
|
reinterpret_cast<uv_handle_t*>(&handle_),
|
|
|
|
AsyncWrap::PROVIDER_FSEVENTWRAP) {}
|
|
|
|
|
|
|
|
|
|
|
|
FSEventWrap::~FSEventWrap() {
|
|
|
|
CHECK_EQ(initialized_, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FSEventWrap::Initialize(Local<Object> target,
|
|
|
|
Local<Value> unused,
|
|
|
|
Local<Context> context) {
|
|
|
|
Environment* env = Environment::GetCurrent(context);
|
|
|
|
|
|
|
|
auto fsevent_string = FIXED_ONE_BYTE_STRING(env->isolate(), "FSEvent");
|
|
|
|
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
|
|
|
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
|
|
|
t->SetClassName(fsevent_string);
|
|
|
|
|
async_wrap,src: add GetAsyncId() method
Allow handles to retrieve their own uid's by adding a new method on the
FunctionTemplates. Implementation of these into all other classes will
come in a future commit.
Add the method AsyncWrap::GetAsyncId() to all inheriting class objects
so the uid of the handle can be retrieved from JS.
In all applicable locations, run ClearWrap() on the object holding the
pointer so that it never points to invalid memory and make sure Wrap()
is always run so the class pointer is correctly attached to the object
and can be retrieved so GetAsyncId() can be run.
In many places a class instance was not removing its own pointer from
object() in the destructor. This left an invalid pointer in the JS
object that could cause the application to segfault under certain
conditions.
Remove ClearWrap() from ReqWrap for continuity. The ReqWrap constructor
was not the one to call Wrap(), so it shouldn't be the one to call
ClearWrap().
Wrap() has been added to all constructors that inherit from AsyncWrap.
Normally it's the child most class. Except in the case of HandleWrap.
Which must be the constructor that runs Wrap() because the class pointer
is retrieved for certain calls and because other child classes have
multiple inheritance to pointer to the HandleWrap needs to be stored.
ClearWrap() has been placed in all FunctionTemplate constructors so that
no random values are returned when running getAsyncId(). ClearWrap() has
also been placed in all class destructors, except in those that use
MakeWeak() because the destructor will run during GC. Making the
object() inaccessible.
It could be simplified to where AsyncWrap sets the internal pointer,
then if an inheriting class needs one of it's own it could set it again.
But the inverse would need to be true also, where AsyncWrap then also
runs ClearWeak. Unforunately because some of the handles are cleaned up
during GC that's impossible. Also in the case of ReqWrap it runs Reset()
in the destructor, making the object() inaccessible. Meaning,
ClearWrap() must be run by the class that runs Wrap(). There's currently
no generalized way of taking care of this across all instances of
AsyncWrap.
I'd prefer that there be checks in there for these things, but haven't
found a way to place them that wouldn't be just as unreliable.
Add test that checks all resources that can run getAsyncId(). Would like
a way to enforce that any new classes that can also run getAsyncId() are
tested, but don't have one.
PR-URL: https://github.com/nodejs/node/pull/12892
Ref: https://github.com/nodejs/node/pull/11883
Ref: https://github.com/nodejs/node/pull/8531
Reviewed-By: Andreas Madsen <amwebdk@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
8 years ago
|
|
|
env->SetProtoMethod(t, "getAsyncId", AsyncWrap::GetAsyncId);
|
|
|
|
env->SetProtoMethod(t, "start", Start);
|
|
|
|
env->SetProtoMethod(t, "close", Close);
|
|
|
|
|
|
|
|
target->Set(fsevent_string, t->GetFunction());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FSEventWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
CHECK(args.IsConstructCall());
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
new FSEventWrap(env, args.This());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
|
|
|
|
FSEventWrap* wrap;
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
|
|
CHECK_EQ(wrap->initialized_, false);
|
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
9 years ago
|
|
|
static const char kErrMsg[] = "filename must be a string or Buffer";
|
|
|
|
if (args.Length() < 1)
|
|
|
|
return env->ThrowTypeError(kErrMsg);
|
|
|
|
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
9 years ago
|
|
|
BufferValue path(env->isolate(), args[0]);
|
|
|
|
if (*path == nullptr)
|
|
|
|
return env->ThrowTypeError(kErrMsg);
|
|
|
|
|
|
|
|
unsigned int flags = 0;
|
|
|
|
if (args[2]->IsTrue())
|
|
|
|
flags |= UV_FS_EVENT_RECURSIVE;
|
|
|
|
|
|
|
|
wrap->encoding_ = ParseEncoding(env->isolate(), args[3], kDefaultEncoding);
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
9 years ago
|
|
|
|
|
|
|
int err = uv_fs_event_init(wrap->env()->event_loop(), &wrap->handle_);
|
|
|
|
if (err == 0) {
|
|
|
|
wrap->initialized_ = true;
|
|
|
|
|
|
|
|
err = uv_fs_event_start(&wrap->handle_, OnEvent, *path, flags);
|
|
|
|
|
|
|
|
if (err == 0) {
|
|
|
|
// Check for persistent argument
|
|
|
|
if (!args[1]->IsTrue()) {
|
|
|
|
uv_unref(reinterpret_cast<uv_handle_t*>(&wrap->handle_));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
FSEventWrap::Close(args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
args.GetReturnValue().Set(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FSEventWrap::OnEvent(uv_fs_event_t* handle, const char* filename,
|
|
|
|
int events, int status) {
|
|
|
|
FSEventWrap* wrap = static_cast<FSEventWrap*>(handle->data);
|
|
|
|
Environment* env = wrap->env();
|
|
|
|
|
|
|
|
HandleScope handle_scope(env->isolate());
|
|
|
|
Context::Scope context_scope(env->context());
|
|
|
|
|
|
|
|
CHECK_EQ(wrap->persistent().IsEmpty(), false);
|
|
|
|
|
|
|
|
// We're in a bind here. libuv can set both UV_RENAME and UV_CHANGE but
|
|
|
|
// the Node API only lets us pass a single event to JS land.
|
|
|
|
//
|
|
|
|
// The obvious solution is to run the callback twice, once for each event.
|
|
|
|
// However, since the second event is not allowed to fire if the handle is
|
|
|
|
// closed after the first event, and since there is no good way to detect
|
|
|
|
// closed handles, that option is out.
|
|
|
|
//
|
|
|
|
// For now, ignore the UV_CHANGE event if UV_RENAME is also set. Make the
|
|
|
|
// assumption that a rename implicitly means an attribute change. Not too
|
|
|
|
// unreasonable, right? Still, we should revisit this before v1.0.
|
|
|
|
Local<String> event_string;
|
|
|
|
if (status) {
|
|
|
|
event_string = String::Empty(env->isolate());
|
|
|
|
} else if (events & UV_RENAME) {
|
|
|
|
event_string = env->rename_string();
|
|
|
|
} else if (events & UV_CHANGE) {
|
|
|
|
event_string = env->change_string();
|
|
|
|
} else {
|
|
|
|
CHECK(0 && "bad fs events flag");
|
|
|
|
}
|
|
|
|
|
|
|
|
Local<Value> argv[] = {
|
|
|
|
Integer::New(env->isolate(), status),
|
|
|
|
event_string,
|
|
|
|
Null(env->isolate())
|
|
|
|
};
|
|
|
|
|
|
|
|
if (filename != nullptr) {
|
|
|
|
Local<Value> error;
|
|
|
|
MaybeLocal<Value> fn = StringBytes::Encode(env->isolate(),
|
|
|
|
filename,
|
|
|
|
wrap->encoding_,
|
|
|
|
&error);
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
9 years ago
|
|
|
if (fn.IsEmpty()) {
|
|
|
|
argv[0] = Integer::New(env->isolate(), UV_EINVAL);
|
|
|
|
argv[2] = StringBytes::Encode(env->isolate(),
|
|
|
|
filename,
|
|
|
|
strlen(filename),
|
|
|
|
BUFFER,
|
|
|
|
&error).ToLocalChecked();
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
9 years ago
|
|
|
} else {
|
|
|
|
argv[2] = fn.ToLocalChecked();
|
fs: Buffer and encoding enhancements to fs API
This makes several changes:
1. Allow path/filename to be passed in as a Buffer on fs methods
2. Add `options.encoding` to fs.readdir, fs.readdirSync, fs.readlink,
fs.readlinkSync and fs.watch.
3. Documentation updates
For 1... it's now possible to do:
```js
fs.open(Buffer('/fs/foo/bar'), 'w+', (err, fd) => { });
```
For 2...
```js
fs.readdir('/fs/foo/bar', {encoding:'hex'}, (err,list) => { });
fs.readdir('/fs/foo/bar', {encoding:'buffer'}, (err, list) => { });
```
encoding can also be passed as a string
```js
fs.readdir('/fs/foo/bar', 'hex', (err,list) => { });
```
The default encoding is set to UTF8 so this addresses the
discrepency that existed previously between fs.readdir and
fs.watch handling filenames differently.
Fixes: https://github.com/nodejs/node/issues/2088
Refs: https://github.com/nodejs/node/issues/3519
PR-URL: https://github.com/nodejs/node/pull/5616
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
9 years ago
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void FSEventWrap::Close(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
FSEventWrap* wrap;
|
|
|
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
|
|
|
|
|
|
if (wrap == nullptr || wrap->initialized_ == false)
|
|
|
|
return;
|
|
|
|
wrap->initialized_ = false;
|
|
|
|
|
|
|
|
HandleWrap::Close(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
} // namespace node
|
|
|
|
|
|
|
|
NODE_MODULE_CONTEXT_AWARE_BUILTIN(fs_event_wrap, node::FSEventWrap::Initialize)
|