From c7944a7a7bd92a446ea81d774ccad31e0e7c8a3f Mon Sep 17 00:00:00 2001 From: Bryan English Date: Fri, 27 Jul 2018 19:29:32 -0700 Subject: 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 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Benjamin Gruenbaum Reviewed-By: Roman Reiss Reviewed-By: John-David Dalton --- src/node_file.cc | 217 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 174 insertions(+), 43 deletions(-) (limited to 'src/node_file.cc') 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 error; - int r; - Local names = Array::New(env->isolate(), 0); - Local fn = env->push_values_to_array_function(); - Local name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; - size_t name_idx = 0; + if (!after.Proceed()) { + return; + } + Environment* env = req_wrap->env(); + Local error; + int r; + Local names = Array::New(env->isolate(), 0); + Local fn = env->push_values_to_array_function(); + Local 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(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(req->path))); + } + + MaybeLocal 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 ret = fn->Call(env->context(), names, name_idx, + name_argv); + if (ret.IsEmpty()) { + return; } + name_idx = 0; + } + } - MaybeLocal 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 error; + int r; + Local names = Array::New(env->isolate(), 0); + Local fn = env->push_values_to_array_function(); + Local name_argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; + size_t name_idx = 0; + Local types = Array::New(env->isolate(), 0); + Local 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(req->path))); + } + + MaybeLocal 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 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 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 ret = fn->Call(env->context(), names, name_idx, + name_argv); + if (ret.IsEmpty()) { + return; + } + } + + if (type_idx > 0) { + MaybeLocal ret = fn->Call(env->context(), types, type_idx, + type_argv); + if (ret.IsEmpty()) { + return; + } } + + Local 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& 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& args) { Local name_v[NODE_PUSH_VAL_TO_ARRAY_MAX]; size_t name_idx = 0; + Local types; + Local 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& args) { if (r == UV_EOF) break; if (r != 0) { - Local ctx = args[3].As(); + Local ctx = args[4].As(); 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& args) { ent.name, encoding, &error); + if (filename.IsEmpty()) { - Local ctx = args[3].As(); + Local ctx = args[4].As(); ctx->Set(env->context(), env->error_string(), error).FromJust(); return; } @@ -1430,6 +1534,19 @@ static void ReadDir(const FunctionCallbackInfo& args) { } name_idx = 0; } + + if (with_types) { + type_v[type_idx++] = Integer::New(env->isolate(), ent.type); + + if (type_idx >= arraysize(type_v)) { + MaybeLocal 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& args) { } } - args.GetReturnValue().Set(names); + if (with_types && type_idx > 0) { + MaybeLocal ret = fn->Call(env->context(), types, type_idx, type_v); + if (ret.IsEmpty()) { + return; + } + } + + if (with_types) { + Local result = Array::New(env->isolate(), 2); + result->Set(0, names); + result->Set(1, types); + args.GetReturnValue().Set(result); + } else { + args.GetReturnValue().Set(names); + } } } -- cgit v1.2.3