diff options
author | Bryan English <bryan@bryanenglish.com> | 2018-07-27 19:29:32 -0700 |
---|---|---|
committer | Bryan English <bryan@bryanenglish.com> | 2018-08-13 19:18:45 -0700 |
commit | c7944a7a7bd92a446ea81d774ccad31e0e7c8a3f (patch) | |
tree | c7b86a281f2af282e080b34965debcea28caf2b7 /src/node_file.cc | |
parent | 78584b64d88c0567c46e3cf7bae42aa73927df40 (diff) | |
download | node-new-c7944a7a7bd92a446ea81d774ccad31e0e7c8a3f.tar.gz |
fs: readdir optionally returning type information
readdir and readdirSync now have a "withFileTypes" option, which, when
enabled, provides an array of DirectoryEntry objects, similar to Stats
objects, which have the filename and the type information.
Refs: https://github.com/nodejs/node/issues/15699
PR-URL: https://github.com/nodejs/node/pull/22020
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Roman Reiss <me@silverwind.io>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Diffstat (limited to 'src/node_file.cc')
-rw-r--r-- | src/node_file.cc | 217 |
1 files changed, 174 insertions, 43 deletions
diff --git a/src/node_file.cc b/src/node_file.cc index 714dec157b..fb976a31a5 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -561,51 +561,139 @@ void AfterScanDir(uv_fs_t* req) { FSReqBase* req_wrap = FSReqBase::from_req(req); FSReqAfterScope after(req_wrap, req); - if (after.Proceed()) { - Environment* env = req_wrap->env(); - Local<Value> error; - int r; - Local<Array> names = Array::New(env->isolate(), 0); - Local<Function> fn = env->push_values_to_array_function(); - Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; - size_t name_idx = 0; + if (!after.Proceed()) { + return; + } + Environment* env = req_wrap->env(); + Local<Value> error; + int r; + Local<Array> names = Array::New(env->isolate(), 0); + Local<Function> fn = env->push_values_to_array_function(); + Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; + size_t name_idx = 0; - for (int i = 0; ; i++) { - uv_dirent_t ent; + for (int i = 0; ; i++) { + uv_dirent_t ent; - r = uv_fs_scandir_next(req, &ent); - if (r == UV_EOF) - break; - if (r != 0) { - return req_wrap->Reject( - UVException(r, nullptr, req_wrap->syscall(), - static_cast<const char*>(req->path))); + r = uv_fs_scandir_next(req, &ent); + if (r == UV_EOF) + break; + if (r != 0) { + return req_wrap->Reject( + UVException(r, nullptr, req_wrap->syscall(), + static_cast<const char*>(req->path))); + } + + MaybeLocal<Value> filename = + StringBytes::Encode(env->isolate(), + ent.name, + req_wrap->encoding(), + &error); + if (filename.IsEmpty()) + return req_wrap->Reject(error); + + name_argv[name_idx++] = filename.ToLocalChecked(); + + if (name_idx >= arraysize(name_argv)) { + MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx, + name_argv); + if (ret.IsEmpty()) { + return; } + name_idx = 0; + } + } - MaybeLocal<Value> filename = - StringBytes::Encode(env->isolate(), - ent.name, - req_wrap->encoding(), - &error); - if (filename.IsEmpty()) - return req_wrap->Reject(error); + if (name_idx > 0) { + fn->Call(env->context(), names, name_idx, name_argv) + .ToLocalChecked(); + } - name_argv[name_idx++] = filename.ToLocalChecked(); + req_wrap->Resolve(names); +} - if (name_idx >= arraysize(name_argv)) { - fn->Call(env->context(), names, name_idx, name_argv) - .ToLocalChecked(); - name_idx = 0; +void AfterScanDirWithTypes(uv_fs_t* req) { + FSReqBase* req_wrap = FSReqBase::from_req(req); + FSReqAfterScope after(req_wrap, req); + + if (!after.Proceed()) { + return; + } + + Environment* env = req_wrap->env(); + Local<Value> error; + int r; + Local<Array> names = Array::New(env->isolate(), 0); + Local<Function> fn = env->push_values_to_array_function(); + Local<Value> name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; + size_t name_idx = 0; + Local<Value> types = Array::New(env->isolate(), 0); + Local<Value> type_argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; + size_t type_idx = 0; + + for (int i = 0; ; i++) { + uv_dirent_t ent; + + r = uv_fs_scandir_next(req, &ent); + if (r == UV_EOF) + break; + if (r != 0) { + return req_wrap->Reject( + UVException(r, nullptr, req_wrap->syscall(), + static_cast<const char*>(req->path))); + } + + MaybeLocal<Value> filename = + StringBytes::Encode(env->isolate(), + ent.name, + req_wrap->encoding(), + &error); + if (filename.IsEmpty()) + return req_wrap->Reject(error); + + name_argv[name_idx++] = filename.ToLocalChecked(); + + if (name_idx >= arraysize(name_argv)) { + MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx, + name_argv); + if (ret.IsEmpty()) { + return; } + name_idx = 0; } - if (name_idx > 0) { - fn->Call(env->context(), names, name_idx, name_argv) - .ToLocalChecked(); + type_argv[type_idx++] = Integer::New(env->isolate(), ent.type); + + if (type_idx >= arraysize(type_argv)) { + MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx, + type_argv); + if (ret.IsEmpty()) { + return; + } + type_idx = 0; } + } - req_wrap->Resolve(names); + if (name_idx > 0) { + MaybeLocal<Value> ret = fn->Call(env->context(), names, name_idx, + name_argv); + if (ret.IsEmpty()) { + return; + } + } + + if (type_idx > 0) { + MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx, + type_argv); + if (ret.IsEmpty()) { + return; + } } + + Local<Array> result = Array::New(env->isolate(), 2); + result->Set(0, names); + result->Set(1, types); + req_wrap->Resolve(result); } @@ -1372,15 +1460,22 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { const enum encoding encoding = ParseEncoding(env->isolate(), args[1], UTF8); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); - if (req_wrap_async != nullptr) { // readdir(path, encoding, req) - AsyncCall(env, req_wrap_async, args, "scandir", encoding, AfterScanDir, - uv_fs_scandir, *path, 0 /*flags*/); - } else { // readdir(path, encoding, undefined, ctx) - CHECK_EQ(argc, 4); + bool with_types = args[2]->BooleanValue(); + + FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + if (req_wrap_async != nullptr) { // readdir(path, encoding, withTypes, req) + if (with_types) { + AsyncCall(env, req_wrap_async, args, "scandir", encoding, + AfterScanDirWithTypes, uv_fs_scandir, *path, 0 /*flags*/); + } else { + AsyncCall(env, req_wrap_async, args, "scandir", encoding, + AfterScanDir, uv_fs_scandir, *path, 0 /*flags*/); + } + } else { // readdir(path, encoding, withTypes, undefined, ctx) + CHECK_EQ(argc, 5); FSReqWrapSync req_wrap_sync; FS_SYNC_TRACE_BEGIN(readdir); - int err = SyncCall(env, args[3], &req_wrap_sync, "scandir", + int err = SyncCall(env, args[4], &req_wrap_sync, "scandir", uv_fs_scandir, *path, 0 /*flags*/); FS_SYNC_TRACE_END(readdir); if (err < 0) { @@ -1394,6 +1489,14 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { Local<Value> name_v[NODE_PUSH_VAL_TO_ARRAY_MAX]; size_t name_idx = 0; + Local<Value> types; + Local<Value> type_v[NODE_PUSH_VAL_TO_ARRAY_MAX]; + size_t type_idx; + if (with_types) { + types = Array::New(env->isolate(), 0); + type_idx = 0; + } + for (int i = 0; ; i++) { uv_dirent_t ent; @@ -1401,7 +1504,7 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { if (r == UV_EOF) break; if (r != 0) { - Local<Object> ctx = args[3].As<Object>(); + Local<Object> ctx = args[4].As<Object>(); ctx->Set(env->context(), env->errno_string(), Integer::New(env->isolate(), r)).FromJust(); ctx->Set(env->context(), env->syscall_string(), @@ -1414,8 +1517,9 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { ent.name, encoding, &error); + if (filename.IsEmpty()) { - Local<Object> ctx = args[3].As<Object>(); + Local<Object> ctx = args[4].As<Object>(); ctx->Set(env->context(), env->error_string(), error).FromJust(); return; } @@ -1430,6 +1534,19 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { } name_idx = 0; } + + if (with_types) { + type_v[type_idx++] = Integer::New(env->isolate(), ent.type); + + if (type_idx >= arraysize(type_v)) { + MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx, + type_v); + if (ret.IsEmpty()) { + return; + } + type_idx = 0; + } + } } if (name_idx > 0) { @@ -1439,7 +1556,21 @@ static void ReadDir(const FunctionCallbackInfo<Value>& args) { } } - args.GetReturnValue().Set(names); + if (with_types && type_idx > 0) { + MaybeLocal<Value> ret = fn->Call(env->context(), types, type_idx, type_v); + if (ret.IsEmpty()) { + return; + } + } + + if (with_types) { + Local<Array> result = Array::New(env->isolate(), 2); + result->Set(0, names); + result->Set(1, types); + args.GetReturnValue().Set(result); + } else { + args.GetReturnValue().Set(names); + } } } |