diff --git a/benchmark/fs/bench-unlinkSync.js b/benchmark/fs/bench-unlinkSync.js new file mode 100644 index 00000000000000..8b992198c8d368 --- /dev/null +++ b/benchmark/fs/bench-unlinkSync.js @@ -0,0 +1,43 @@ +'use strict'; + +const common = require('../common'); +const fs = require('fs'); +const tmpdir = require('../../test/common/tmpdir'); +tmpdir.refresh(); + +const bench = common.createBenchmark(main, { + type: ['existing', 'non-existing'], + n: [1e3], +}); + +function main({ n, type }) { + let files; + + switch (type) { + case 'existing': + files = []; + + // Populate tmpdir with mock files + for (let i = 0; i < n; i++) { + const path = tmpdir.resolve(`unlinksync-bench-file-${i}`); + fs.writeFileSync(path, 'bench'); + files.push(path); + } + break; + case 'non-existing': + files = new Array(n).fill(tmpdir.resolve(`.non-existing-file-${Date.now()}`)); + break; + default: + new Error('Invalid type'); + } + + bench.start(); + for (let i = 0; i < n; i++) { + try { + fs.unlinkSync(files[i]); + } catch { + // do nothing + } + } + bench.end(n); +} diff --git a/lib/fs.js b/lib/fs.js index 9b6b61dc8efd42..29f356a57cd22e 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1850,10 +1850,7 @@ function unlink(path, callback) { * @returns {void} */ function unlinkSync(path) { - path = getValidatedPath(path); - const ctx = { path }; - binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx); - handleErrorFromBinding(ctx); + return syncFs.unlink(path); } /** diff --git a/lib/internal/fs/sync.js b/lib/internal/fs/sync.js index 0d4ba90150e186..fbcc2ad2e25b2a 100644 --- a/lib/internal/fs/sync.js +++ b/lib/internal/fs/sync.js @@ -88,6 +88,11 @@ function close(fd) { return binding.closeSync(fd); } +function unlink(path) { + path = pathModule.toNamespacedPath(getValidatedPath(path)); + return binding.unlinkSync(path); +} + module.exports = { readFileUtf8, exists, @@ -97,4 +102,5 @@ module.exports = { statfs, open, close, + unlink, }; diff --git a/src/node_file.cc b/src/node_file.cc index 7ac61d55797061..293681b7e4ed2b 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -1702,6 +1702,27 @@ static void Unlink(const FunctionCallbackInfo& args) { } } +static void UnlinkSync(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + const int argc = args.Length(); + CHECK_GE(argc, 1); + + BufferValue path(env->isolate(), args[0]); + CHECK_NOT_NULL(*path); + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); + + uv_fs_t req; + auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); }); + FS_SYNC_TRACE_BEGIN(unlink); + int err = uv_fs_unlink(nullptr, &req, *path, nullptr); + FS_SYNC_TRACE_END(unlink); + if (err < 0) { + return env->ThrowUVException(err, "unlink", nullptr, *path); + } +} + static void RMDir(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -3425,6 +3446,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, SetMethod(isolate, target, "symlink", Symlink); SetMethod(isolate, target, "readlink", ReadLink); SetMethod(isolate, target, "unlink", Unlink); + SetMethod(isolate, target, "unlinkSync", UnlinkSync); SetMethod(isolate, target, "writeBuffer", WriteBuffer); SetMethod(isolate, target, "writeBuffers", WriteBuffers); SetMethod(isolate, target, "writeString", WriteString); @@ -3550,6 +3572,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(Symlink); registry->Register(ReadLink); registry->Register(Unlink); + registry->Register(UnlinkSync); registry->Register(WriteBuffer); registry->Register(WriteBuffers); registry->Register(WriteString);