1+ #include " node_constants.h"
12#include " node_file_sync.h"
23#include " memory_tracker-inl.h"
34#include " node_buffer.h"
1617
1718#include < fcntl.h>
1819
20+ #if !defined(_MSC_VER)
21+ #include < unistd.h>
22+ #endif
23+
1924namespace node {
2025namespace fs_sync {
2126
2227using v8::Array;
28+ using v8::CFunction;
2329using v8::Context;
2430using v8::FunctionCallbackInfo;
2531using v8::HandleScope;
2632using v8::Int32;
2733using v8::Integer;
2834using v8::Isolate;
35+ using v8::FastOneByteString;
2936using v8::JustVoid;
3037using v8::Local;
3138using v8::Maybe;
@@ -115,6 +122,50 @@ void BindingData::Deserialize(v8::Local<v8::Context> context,
115122 CHECK_NOT_NULL (binding);
116123}
117124
125+ bool BindingData::ExistsInternal (const std::string_view path) {
126+ uv_fs_t req;
127+ auto make = OnScopeLeave ([&req]() { uv_fs_req_cleanup (&req); });
128+ FS_SYNC_TRACE_BEGIN (access);
129+ int err = uv_fs_access (nullptr , &req, path.data (), F_OK, nullptr );
130+ FS_SYNC_TRACE_END (access);
131+
132+ #ifdef _WIN32
133+ // In case of an invalid symlink, `binding.access()` on win32
134+ // will **not** return an error and is therefore not enough.
135+ // Double check with `stat()`.
136+ if (err != 0 ) {
137+ FS_SYNC_TRACE_BEGIN (stat);
138+ err = uv_fs_stat (nullptr , &req, path.data , nullptr );
139+ FS_SYNC_TRACE_END (stat);
140+ }
141+ #endif // _WIN32
142+
143+ return err == 0 ;
144+ }
145+
146+ void BindingData::Exists (const FunctionCallbackInfo<Value>& args) {
147+ Environment* env = Environment::GetCurrent (args);
148+ Isolate* isolate = env->isolate ();
149+
150+ const int argc = args.Length ();
151+ CHECK_GE (argc, 1 );
152+
153+ BufferValue path (isolate, args[0 ]);
154+ CHECK_NOT_NULL (*path);
155+ THROW_IF_INSUFFICIENT_PERMISSIONS (
156+ env, permission::PermissionScope::kFileSystemRead , path.ToStringView ());
157+
158+ return ExistsInternal (path.ToStringView ());
159+ }
160+
161+ bool BindingData::FastExists (Local<Value> receiver,
162+ const FastOneByteString& path) {
163+ // TODO(@anonrig): Add "THROW_IF_INSUFFICIENT_PERMISSIONS"
164+ return ExistsInternal (std::string_view (path.data , path.length ));
165+ }
166+
167+ CFunction BindingData::fast_exists_ (CFunction::Make(FastExists));
168+
118169void BindingData::ReadFileUtf8 (const FunctionCallbackInfo<Value>& args) {
119170 Environment* env = Environment::GetCurrent (args);
120171 auto isolate = env->isolate ();
@@ -186,6 +237,7 @@ void BindingData::ReadFileUtf8(const FunctionCallbackInfo<Value>& args) {
186237void BindingData::CreatePerIsolateProperties (IsolateData* isolate_data,
187238 Local<ObjectTemplate> target) {
188239 Isolate* isolate = isolate_data->isolate ();
240+ SetFastMethodNoSideEffect (isolate, target, " exists" , Exists, &fast_exists_);
189241 SetMethodNoSideEffect (isolate, target, " readFileUtf8" , ReadFileUtf8);
190242}
191243
@@ -199,6 +251,9 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
199251
200252void BindingData::RegisterExternalReferences (
201253 ExternalReferenceRegistry* registry) {
254+ registry->Register (Exists);
255+ registry->Register (FastExists);
256+ registry->Register (fast_exists_.GetTypeInfo ());
202257 registry->Register (ReadFileUtf8);
203258}
204259
0 commit comments