Skip to content

Commit f16f41c

Browse files
authored
fs: improve readFileSync with file descriptors
PR-URL: #49691 Reviewed-By: Stephen Belanger <[email protected]>
1 parent 717e233 commit f16f41c

File tree

4 files changed

+50
-27
lines changed

4 files changed

+50
-27
lines changed

benchmark/fs/readFileSync.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,21 @@ const fs = require('fs');
66
const bench = common.createBenchmark(main, {
77
encoding: ['undefined', 'utf8'],
88
path: ['existing', 'non-existing'],
9-
n: [60e1],
9+
hasFileDescriptor: ['true', 'false'],
10+
n: [1e4],
1011
});
1112

12-
function main({ n, encoding, path }) {
13+
function main({ n, encoding, path, hasFileDescriptor }) {
1314
const enc = encoding === 'undefined' ? undefined : encoding;
14-
const file = path === 'existing' ? __filename : '/tmp/not-found';
15+
let file;
16+
let shouldClose = false;
17+
18+
if (hasFileDescriptor === 'true') {
19+
shouldClose = path === 'existing';
20+
file = path === 'existing' ? fs.openSync(__filename) : -1;
21+
} else {
22+
file = path === 'existing' ? __filename : '/tmp/not-found';
23+
}
1524
bench.start();
1625
for (let i = 0; i < n; ++i) {
1726
try {
@@ -21,4 +30,7 @@ function main({ n, encoding, path }) {
2130
}
2231
}
2332
bench.end(n);
33+
if (shouldClose) {
34+
fs.closeSync(file);
35+
}
2436
}

lib/fs.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -437,13 +437,11 @@ function tryReadSync(fd, isUserFd, buffer, pos, len) {
437437
function readFileSync(path, options) {
438438
options = getOptions(options, { flag: 'r' });
439439

440-
const isUserFd = isFd(path); // File descriptor ownership
441-
442-
// TODO(@anonrig): Do not handle file descriptor ownership for now.
443-
if (!isUserFd && (options.encoding === 'utf8' || options.encoding === 'utf-8')) {
440+
if (options.encoding === 'utf8' || options.encoding === 'utf-8') {
444441
return syncFs.readFileUtf8(path, options.flag);
445442
}
446443

444+
const isUserFd = isFd(path); // File descriptor ownership
447445
const fd = isUserFd ? path : fs.openSync(path, options.flag, 0o666);
448446

449447
const stats = tryStatSync(fd, isUserFd);

lib/internal/fs/sync.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const {
99
getStatFsFromBinding,
1010
getValidatedFd,
1111
} = require('internal/fs/utils');
12-
const { parseFileMode } = require('internal/validators');
12+
const { parseFileMode, isInt32 } = require('internal/validators');
1313

1414
const binding = internalBinding('fs');
1515

@@ -19,7 +19,9 @@ const binding = internalBinding('fs');
1919
* @return {string}
2020
*/
2121
function readFileUtf8(path, flag) {
22-
path = pathModule.toNamespacedPath(getValidatedPath(path));
22+
if (!isInt32(path)) {
23+
path = pathModule.toNamespacedPath(getValidatedPath(path));
24+
}
2325
return binding.readFileUtf8(path, stringToFlags(flag));
2426
}
2527

src/node_file.cc

+29-18
Original file line numberDiff line numberDiff line change
@@ -2155,7 +2155,7 @@ static void OpenSync(const FunctionCallbackInfo<Value>& args) {
21552155
uv_fs_t req;
21562156
auto make = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
21572157
FS_SYNC_TRACE_BEGIN(open);
2158-
int err = uv_fs_open(nullptr, &req, *path, flags, mode, nullptr);
2158+
auto err = uv_fs_open(nullptr, &req, *path, flags, mode, nullptr);
21592159
FS_SYNC_TRACE_END(open);
21602160
if (err < 0) {
21612161
return env->ThrowUVException(err, "open", nullptr, path.out());
@@ -2546,30 +2546,41 @@ static void ReadFileUtf8(const FunctionCallbackInfo<Value>& args) {
25462546

25472547
CHECK_GE(args.Length(), 2);
25482548

2549-
BufferValue path(env->isolate(), args[0]);
2550-
CHECK_NOT_NULL(*path);
2551-
25522549
CHECK(args[1]->IsInt32());
25532550
const int flags = args[1].As<Int32>()->Value();
25542551

2555-
if (CheckOpenPermissions(env, path, flags).IsNothing()) return;
2556-
2552+
uv_file file;
25572553
uv_fs_t req;
2558-
auto defer_req_cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });
25592554

2560-
FS_SYNC_TRACE_BEGIN(open);
2561-
uv_file file = uv_fs_open(nullptr, &req, *path, flags, 438, nullptr);
2562-
FS_SYNC_TRACE_END(open);
2563-
if (req.result < 0) {
2564-
// req will be cleaned up by scope leave.
2565-
return env->ThrowUVException(req.result, "open", nullptr, path.out());
2555+
bool is_fd = args[0]->IsInt32();
2556+
2557+
// Check for file descriptor
2558+
if (is_fd) {
2559+
file = args[0].As<Int32>()->Value();
2560+
} else {
2561+
BufferValue path(env->isolate(), args[0]);
2562+
CHECK_NOT_NULL(*path);
2563+
if (CheckOpenPermissions(env, path, flags).IsNothing()) return;
2564+
2565+
FS_SYNC_TRACE_BEGIN(open);
2566+
file = uv_fs_open(nullptr, &req, *path, flags, O_RDONLY, nullptr);
2567+
FS_SYNC_TRACE_END(open);
2568+
if (req.result < 0) {
2569+
uv_fs_req_cleanup(&req);
2570+
// req will be cleaned up by scope leave.
2571+
return env->ThrowUVException(req.result, "open", nullptr, path.out());
2572+
}
25662573
}
25672574

2568-
auto defer_close = OnScopeLeave([file]() {
2569-
uv_fs_t close_req;
2570-
CHECK_EQ(0, uv_fs_close(nullptr, &close_req, file, nullptr));
2571-
uv_fs_req_cleanup(&close_req);
2575+
auto defer_close = OnScopeLeave([file, is_fd, &req]() {
2576+
if (!is_fd) {
2577+
FS_SYNC_TRACE_BEGIN(close);
2578+
CHECK_EQ(0, uv_fs_close(nullptr, &req, file, nullptr));
2579+
FS_SYNC_TRACE_END(close);
2580+
}
2581+
uv_fs_req_cleanup(&req);
25722582
});
2583+
25732584
std::string result{};
25742585
char buffer[8192];
25752586
uv_buf_t buf = uv_buf_init(buffer, sizeof(buffer));
@@ -2580,7 +2591,7 @@ static void ReadFileUtf8(const FunctionCallbackInfo<Value>& args) {
25802591
if (req.result < 0) {
25812592
FS_SYNC_TRACE_END(read);
25822593
// req will be cleaned up by scope leave.
2583-
return env->ThrowUVException(req.result, "read", nullptr, path.out());
2594+
return env->ThrowUVException(req.result, "read", nullptr);
25842595
}
25852596
if (r <= 0) {
25862597
break;

0 commit comments

Comments
 (0)