diff --git a/src/node_file.cc b/src/node_file.cc index e34dec1d6473a4..3531708fef53dc 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -2853,10 +2853,10 @@ static void Chown(const FunctionCallbackInfo& args) { ToNamespacedPath(env, &path); CHECK(IsSafeJsInt(args[1])); - const uv_uid_t uid = FromV8Value(args[1]); + const auto uid = FromV8Value(args[1]); CHECK(IsSafeJsInt(args[2])); - const uv_gid_t gid = FromV8Value(args[2]); + const auto gid = FromV8Value(args[2]); if (argc > 3) { // chown(path, uid, gid, req) FSReqBase* req_wrap_async = GetReqWrap(args, 3); @@ -2898,10 +2898,10 @@ static void FChown(const FunctionCallbackInfo& args) { } CHECK(IsSafeJsInt(args[1])); - const uv_uid_t uid = static_cast(args[1].As()->Value()); + const auto uid = FromV8Value(args[1]); CHECK(IsSafeJsInt(args[2])); - const uv_gid_t gid = static_cast(args[2].As()->Value()); + const auto gid = FromV8Value(args[2]); if (argc > 3) { // fchown(fd, uid, gid, req) FSReqBase* req_wrap_async = GetReqWrap(args, 3); @@ -2928,10 +2928,10 @@ static void LChown(const FunctionCallbackInfo& args) { ToNamespacedPath(env, &path); CHECK(IsSafeJsInt(args[1])); - const uv_uid_t uid = FromV8Value(args[1]); + const auto uid = FromV8Value(args[1]); CHECK(IsSafeJsInt(args[2])); - const uv_gid_t gid = FromV8Value(args[2]); + const auto gid = FromV8Value(args[2]); if (argc > 3) { // lchown(path, uid, gid, req) FSReqBase* req_wrap_async = GetReqWrap(args, 3); diff --git a/src/util-inl.h b/src/util-inl.h index 73a09a56bd598d..3493732471fd95 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -627,19 +627,24 @@ constexpr std::string_view FastStringKey::as_string_view() const { // Converts a V8 numeric value to a corresponding C++ primitive or enum type. template ::is_specialized || std::is_enum_v>> T FromV8Value(v8::Local value) { if constexpr (std::is_enum_v) { using Underlying = std::underlying_type_t; - return static_cast(FromV8Value(value)); + return static_cast(FromV8Value(value)); } else if constexpr (std::is_integral_v && std::is_unsigned_v) { static_assert( std::numeric_limits::max() <= std::numeric_limits::max() && std::numeric_limits::min() >= std::numeric_limits::min(), "Type is out of unsigned integer range"); - CHECK(value->IsUint32()); + if constexpr (!loose) { + CHECK(value->IsUint32()); + } else { + CHECK(value->IsNumber()); + } return static_cast(value.As()->Value()); } else if constexpr (std::is_integral_v && std::is_signed_v) { static_assert( @@ -647,7 +652,11 @@ T FromV8Value(v8::Local value) { std::numeric_limits::min() >= std::numeric_limits::min(), "Type is out of signed integer range"); - CHECK(value->IsInt32()); + if constexpr (!loose) { + CHECK(value->IsInt32()); + } else { + CHECK(value->IsNumber()); + } return static_cast(value.As()->Value()); } else { static_assert(std::is_floating_point_v, diff --git a/test/parallel/test-fs-chown-negative-one.js b/test/parallel/test-fs-chown-negative-one.js new file mode 100644 index 00000000000000..092d4782d1154f --- /dev/null +++ b/test/parallel/test-fs-chown-negative-one.js @@ -0,0 +1,32 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const tmpdir = require('../common/tmpdir'); + +tmpdir.refresh(); + +const testFile = path.join(tmpdir.path, 'chown-test-file.txt'); + +fs.writeFileSync(testFile, 'test content for chown'); + +const stats = fs.statSync(testFile); +const uid = stats.uid; +const gid = stats.gid; + +// -1 for uid and gid means "don't change the value" +{ + fs.chown(testFile, -1, -1, common.mustSucceed(() => { + const stats = fs.statSync(testFile); + assert.strictEqual(stats.uid, uid); + assert.strictEqual(stats.gid, gid); + })); +} +{ + fs.chownSync(testFile, -1, -1); + const stats = fs.statSync(testFile); + assert.strictEqual(stats.uid, uid); + assert.strictEqual(stats.gid, gid); +} diff --git a/test/parallel/test-fs-fchown-negative-one.js b/test/parallel/test-fs-fchown-negative-one.js new file mode 100644 index 00000000000000..e88b3a2428fd09 --- /dev/null +++ b/test/parallel/test-fs-fchown-negative-one.js @@ -0,0 +1,42 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const tmpdir = require('../common/tmpdir'); + +tmpdir.refresh(); + +const testFilePath = path.join(tmpdir.path, 'fchown-test-file.txt'); + +fs.writeFileSync(testFilePath, 'test content for fchown'); + +{ + const fd = fs.openSync(testFilePath, 'r+'); + const stats = fs.fstatSync(fd); + const uid = stats.uid; + const gid = stats.gid; + + fs.fchown(fd, -1, -1, common.mustSucceed(() => { + const stats = fs.fstatSync(fd); + assert.strictEqual(stats.uid, uid); + assert.strictEqual(stats.gid, gid); + fs.closeSync(fd); + })); +} + +// Test sync fchown with -1 values +{ + const fd = fs.openSync(testFilePath, 'r+'); + const stats = fs.fstatSync(fd); + const uid = stats.uid; + const gid = stats.gid; + + fs.fchownSync(fd, -1, -1); + const statsAfter = fs.fstatSync(fd); + assert.strictEqual(statsAfter.uid, uid); + assert.strictEqual(statsAfter.gid, gid); + + fs.closeSync(fd); +} diff --git a/test/parallel/test-fs-lchown-negative-one.js b/test/parallel/test-fs-lchown-negative-one.js new file mode 100644 index 00000000000000..d681f3e429b3d2 --- /dev/null +++ b/test/parallel/test-fs-lchown-negative-one.js @@ -0,0 +1,34 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const tmpdir = require('../common/tmpdir'); + +tmpdir.refresh(); + +const testFile = path.join(tmpdir.path, 'lchown-test-file.txt'); +const testLink = path.join(tmpdir.path, 'lchown-test-link'); + +fs.writeFileSync(testFile, 'test content for lchown'); +fs.symlinkSync(testFile, testLink); + +const stats = fs.lstatSync(testLink); +const uid = stats.uid; +const gid = stats.gid; + +// -1 for uid and gid means "don't change the value" +{ + fs.lchown(testLink, -1, -1, common.mustSucceed(() => { + const stats = fs.lstatSync(testLink); + assert.strictEqual(stats.uid, uid); + assert.strictEqual(stats.gid, gid); + })); +} +{ + fs.lchownSync(testLink, -1, -1); + const stats = fs.lstatSync(testLink); + assert.strictEqual(stats.uid, uid); + assert.strictEqual(stats.gid, gid); +}