Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremiah Senkpiel <fishrock123@rocketmail.com>2019-08-28 03:14:27 +0300
committerJeremiah Senkpiel <fishrock123@rocketmail.com>2019-10-08 20:34:48 +0300
commitcbd8d715b2286e5726e6988921f5c870cbf74127 (patch)
tree20c878fd9d7882f2a5b43718a0b3daad4a9a0255 /src/node_file.h
parent064e111515185529b6f943dc66929440557fd609 (diff)
fs: introduce `opendir()` and `fs.Dir`
This adds long-requested methods for asynchronously interacting and iterating through directory entries by using `uv_fs_opendir`, `uv_fs_readdir`, and `uv_fs_closedir`. `fs.opendir()` and friends return an `fs.Dir`, which contains methods for doing reads and cleanup. `fs.Dir` also has the async iterator symbol exposed. The `read()` method and friends only return `fs.Dirent`s for this API. Having a entry type or doing a `stat` call is deemed to be necessary in the majority of cases, so just returning dirents seems like the logical choice for a new api. Reading when there are no more entries returns `null` instead of a dirent. However the async iterator hides that (and does automatic cleanup). The code lives in separate files from the rest of fs, this is done partially to prevent over-pollution of those (already very large) files, but also in the case of js allows loading into `fsPromises`. Due to async_hooks, this introduces a new handle type of `DIRHANDLE`. This PR does not attempt to make complete optimization of this feature. Notable future improvements include: - Moving promise work into C++ land like FileHandle. - Possibly adding `readv()` to do multi-entry directory reads. - Aliasing `fs.readdir` to `fs.scandir` and doing a deprecation. Refs: https://github.com/nodejs/node-v0.x-archive/issues/388 Refs: https://github.com/nodejs/node/issues/583 Refs: https://github.com/libuv/libuv/pull/2057 PR-URL: https://github.com/nodejs/node/pull/29349 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: David Carlier <devnexen@gmail.com>
Diffstat (limited to 'src/node_file.h')
-rw-r--r--src/node_file.h89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/node_file.h b/src/node_file.h
index 2ea5af025d1..84f4032cc2f 100644
--- a/src/node_file.h
+++ b/src/node_file.h
@@ -4,7 +4,9 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "node.h"
+#include "aliased_buffer.h"
#include "stream_base.h"
+#include "memory_tracker-inl.h"
#include "req_wrap-inl.h"
#include <iostream>
@@ -450,6 +452,93 @@ int MKDirpSync(uv_loop_t* loop,
const std::string& path,
int mode,
uv_fs_cb cb = nullptr);
+
+class FSReqWrapSync {
+ public:
+ FSReqWrapSync() = default;
+ ~FSReqWrapSync() { uv_fs_req_cleanup(&req); }
+ uv_fs_t req;
+
+ FSReqWrapSync(const FSReqWrapSync&) = delete;
+ FSReqWrapSync& operator=(const FSReqWrapSync&) = delete;
+};
+
+// TODO(addaleax): Currently, callers check the return value and assume
+// that nullptr indicates a synchronous call, rather than a failure.
+// Failure conditions should be disambiguated and handled appropriately.
+inline FSReqBase* GetReqWrap(Environment* env, v8::Local<v8::Value> value,
+ bool use_bigint = false) {
+ if (value->IsObject()) {
+ return Unwrap<FSReqBase>(value.As<Object>());
+ } else if (value->StrictEquals(env->fs_use_promises_symbol())) {
+ if (use_bigint) {
+ return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
+ } else {
+ return FSReqPromise<AliasedFloat64Array>::New(env, use_bigint);
+ }
+ }
+ return nullptr;
+}
+
+// Returns nullptr if the operation fails from the start.
+template <typename Func, typename... Args>
+inline FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
+ const v8::FunctionCallbackInfo<Value>& args,
+ const char* syscall, const char* dest,
+ size_t len, enum encoding enc, uv_fs_cb after,
+ Func fn, Args... fn_args) {
+ CHECK_NOT_NULL(req_wrap);
+ req_wrap->Init(syscall, dest, len, enc);
+ int err = req_wrap->Dispatch(fn, fn_args..., after);
+ if (err < 0) {
+ uv_fs_t* uv_req = req_wrap->req();
+ uv_req->result = err;
+ uv_req->path = nullptr;
+ after(uv_req); // after may delete req_wrap if there is an error
+ req_wrap = nullptr;
+ } else {
+ req_wrap->SetReturnValue(args);
+ }
+
+ return req_wrap;
+}
+
+// Returns nullptr if the operation fails from the start.
+template <typename Func, typename... Args>
+inline FSReqBase* AsyncCall(Environment* env,
+ FSReqBase* req_wrap,
+ const v8::FunctionCallbackInfo<Value>& args,
+ const char* syscall, enum encoding enc,
+ uv_fs_cb after, Func fn, Args... fn_args) {
+ return AsyncDestCall(env, req_wrap, args,
+ syscall, nullptr, 0, enc,
+ after, fn, fn_args...);
+}
+
+// Template counterpart of SYNC_CALL, except that it only puts
+// the error number and the syscall in the context instead of
+// creating an error in the C++ land.
+// ctx must be checked using value->IsObject() before being passed.
+template <typename Func, typename... Args>
+inline int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
+ FSReqWrapSync* req_wrap, const char* syscall,
+ Func fn, Args... args) {
+ env->PrintSyncTrace();
+ int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
+ if (err < 0) {
+ v8::Local<Context> context = env->context();
+ v8::Local<Object> ctx_obj = ctx.As<v8::Object>();
+ v8::Isolate* isolate = env->isolate();
+ ctx_obj->Set(context,
+ env->errno_string(),
+ v8::Integer::New(isolate, err)).Check();
+ ctx_obj->Set(context,
+ env->syscall_string(),
+ OneByteString(isolate, syscall)).Check();
+ }
+ return err;
+}
+
} // namespace fs
} // namespace node