Skip to content

Commit 04e8f07

Browse files
joyeecheungtargos
authored andcommitted
fs: support BigInt in fs.*stat and fs.watchFile
Add the `bigint: true` option to all the `fs.*stat` methods and `fs.watchFile`. PR-URL: #20220 Fixes: #12115 Reviewed-By: Ben Noordhuis <[email protected]>
1 parent ea4be72 commit 04e8f07

15 files changed

+341
-79
lines changed

lib/fs.js

+34-22
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ function readFileAfterOpen(err, fd) {
248248
const req = new FSReqWrap();
249249
req.oncomplete = readFileAfterStat;
250250
req.context = context;
251-
binding.fstat(fd, req);
251+
binding.fstat(fd, false, req);
252252
}
253253

254254
function readFileAfterStat(err, stats) {
@@ -307,7 +307,7 @@ function readFile(path, options, callback) {
307307

308308
function tryStatSync(fd, isUserFd) {
309309
const ctx = {};
310-
const stats = binding.fstat(fd, undefined, ctx);
310+
const stats = binding.fstat(fd, false, undefined, ctx);
311311
if (ctx.errno !== undefined && !isUserFd) {
312312
fs.closeSync(fd);
313313
throw errors.uvException(ctx);
@@ -760,55 +760,67 @@ function readdirSync(path, options) {
760760
return result;
761761
}
762762

763-
function fstat(fd, callback) {
763+
function fstat(fd, options, callback) {
764+
if (arguments.length < 3) {
765+
callback = options;
766+
options = {};
767+
}
764768
validateUint32(fd, 'fd');
765-
const req = new FSReqWrap();
769+
const req = new FSReqWrap(options.bigint);
766770
req.oncomplete = makeStatsCallback(callback);
767-
binding.fstat(fd, req);
771+
binding.fstat(fd, options.bigint, req);
768772
}
769773

770-
function lstat(path, callback) {
774+
function lstat(path, options, callback) {
775+
if (arguments.length < 3) {
776+
callback = options;
777+
options = {};
778+
}
771779
callback = makeStatsCallback(callback);
772780
path = getPathFromURL(path);
773781
validatePath(path);
774-
const req = new FSReqWrap();
782+
const req = new FSReqWrap(options.bigint);
775783
req.oncomplete = callback;
776-
binding.lstat(pathModule.toNamespacedPath(path), req);
784+
binding.lstat(pathModule.toNamespacedPath(path), options.bigint, req);
777785
}
778786

779-
function stat(path, callback) {
787+
function stat(path, options, callback) {
788+
if (arguments.length < 3) {
789+
callback = options;
790+
options = {};
791+
}
780792
callback = makeStatsCallback(callback);
781793
path = getPathFromURL(path);
782794
validatePath(path);
783-
const req = new FSReqWrap();
795+
const req = new FSReqWrap(options.bigint);
784796
req.oncomplete = callback;
785-
binding.stat(pathModule.toNamespacedPath(path), req);
797+
binding.stat(pathModule.toNamespacedPath(path), options.bigint, req);
786798
}
787799

788-
function fstatSync(fd) {
800+
function fstatSync(fd, options = {}) {
789801
validateUint32(fd, 'fd');
790802
const ctx = { fd };
791-
const stats = binding.fstat(fd, undefined, ctx);
803+
const stats = binding.fstat(fd, options.bigint, undefined, ctx);
792804
handleErrorFromBinding(ctx);
793805
return getStatsFromBinding(stats);
794806
}
795807

796-
function lstatSync(path) {
808+
function lstatSync(path, options = {}) {
797809
path = getPathFromURL(path);
798810
validatePath(path);
799811
const ctx = { path };
800812
const stats = binding.lstat(pathModule.toNamespacedPath(path),
801-
undefined, ctx);
813+
options.bigint, undefined, ctx);
802814
handleErrorFromBinding(ctx);
803815
return getStatsFromBinding(stats);
804816
}
805817

806-
function statSync(path) {
818+
function statSync(path, options = {}) {
807819
path = getPathFromURL(path);
808820
validatePath(path);
809821
const ctx = { path };
810822
const stats = binding.stat(pathModule.toNamespacedPath(path),
811-
undefined, ctx);
823+
options.bigint, undefined, ctx);
812824
handleErrorFromBinding(ctx);
813825
return getStatsFromBinding(stats);
814826
}
@@ -1264,7 +1276,7 @@ function watchFile(filename, options, listener) {
12641276
if (stat === undefined) {
12651277
if (!watchers)
12661278
watchers = require('internal/fs/watchers');
1267-
stat = new watchers.StatWatcher();
1279+
stat = new watchers.StatWatcher(options.bigint);
12681280
stat.start(filename, options.persistent, options.interval);
12691281
statWatchers.set(filename, stat);
12701282
}
@@ -1379,7 +1391,7 @@ function realpathSync(p, options) {
13791391
// On windows, check that the root exists. On unix there is no need.
13801392
if (isWindows && !knownHard[base]) {
13811393
const ctx = { path: base };
1382-
binding.lstat(pathModule.toNamespacedPath(base), undefined, ctx);
1394+
binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx);
13831395
handleErrorFromBinding(ctx);
13841396
knownHard[base] = true;
13851397
}
@@ -1421,7 +1433,7 @@ function realpathSync(p, options) {
14211433

14221434
const baseLong = pathModule.toNamespacedPath(base);
14231435
const ctx = { path: base };
1424-
const stats = binding.lstat(baseLong, undefined, ctx);
1436+
const stats = binding.lstat(baseLong, false, undefined, ctx);
14251437
handleErrorFromBinding(ctx);
14261438

14271439
if (!isFileType(stats, S_IFLNK)) {
@@ -1444,7 +1456,7 @@ function realpathSync(p, options) {
14441456
}
14451457
if (linkTarget === null) {
14461458
const ctx = { path: base };
1447-
binding.stat(baseLong, undefined, ctx);
1459+
binding.stat(baseLong, false, undefined, ctx);
14481460
handleErrorFromBinding(ctx);
14491461
linkTarget = binding.readlink(baseLong, undefined, undefined, ctx);
14501462
handleErrorFromBinding(ctx);
@@ -1465,7 +1477,7 @@ function realpathSync(p, options) {
14651477
// On windows, check that the root exists. On unix there is no need.
14661478
if (isWindows && !knownHard[base]) {
14671479
const ctx = { path: base };
1468-
binding.lstat(pathModule.toNamespacedPath(base), undefined, ctx);
1480+
binding.lstat(pathModule.toNamespacedPath(base), false, undefined, ctx);
14691481
handleErrorFromBinding(ctx);
14701482
knownHard[base] = true;
14711483
}

lib/internal/fs/promises.js

+9-10
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ class FileHandle {
8181
return readFile(this, options);
8282
}
8383

84-
stat() {
85-
return fstat(this);
84+
stat(options) {
85+
return fstat(this, options);
8686
}
8787

8888
truncate(len = 0) {
@@ -106,7 +106,6 @@ class FileHandle {
106106
}
107107
}
108108

109-
110109
function validateFileHandle(handle) {
111110
if (!(handle instanceof FileHandle))
112111
throw new ERR_INVALID_ARG_TYPE('filehandle', 'FileHandle', handle);
@@ -127,7 +126,7 @@ async function writeFileHandle(filehandle, data, options) {
127126
}
128127

129128
async function readFileHandle(filehandle, options) {
130-
const statFields = await binding.fstat(filehandle.fd, kUsePromises);
129+
const statFields = await binding.fstat(filehandle.fd, false, kUsePromises);
131130

132131
let size;
133132
if ((statFields[1/* mode */] & S_IFMT) === S_IFREG) {
@@ -318,25 +317,25 @@ async function symlink(target, path, type_) {
318317
kUsePromises);
319318
}
320319

321-
async function fstat(handle) {
320+
async function fstat(handle, options = { bigint: false }) {
322321
validateFileHandle(handle);
323-
const result = await binding.fstat(handle.fd, kUsePromises);
322+
const result = await binding.fstat(handle.fd, options.bigint, kUsePromises);
324323
return getStatsFromBinding(result);
325324
}
326325

327-
async function lstat(path) {
326+
async function lstat(path, options = { bigint: false }) {
328327
path = getPathFromURL(path);
329328
validatePath(path);
330329
const result = await binding.lstat(pathModule.toNamespacedPath(path),
331-
kUsePromises);
330+
options.bigint, kUsePromises);
332331
return getStatsFromBinding(result);
333332
}
334333

335-
async function stat(path) {
334+
async function stat(path, options = { bigint: false }) {
336335
path = getPathFromURL(path);
337336
validatePath(path);
338337
const result = await binding.stat(pathModule.toNamespacedPath(path),
339-
kUsePromises);
338+
options.bigint, kUsePromises);
340339
return getStatsFromBinding(result);
341340
}
342341

lib/internal/fs/utils.js

+12-4
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ function preprocessSymlinkDestination(path, type, linkPath) {
114114
}
115115

116116
function dateFromNumeric(num) {
117-
return new Date(num + 0.5);
117+
return new Date(Number(num) + 0.5);
118118
}
119119

120120
// Constructor for file stats.
@@ -155,7 +155,15 @@ function Stats(
155155
}
156156

157157
Stats.prototype._checkModeProperty = function(property) {
158-
return ((this.mode & S_IFMT) === property);
158+
if (isWindows && (property === S_IFIFO || property === S_IFBLK ||
159+
property === S_IFSOCK)) {
160+
return false; // Some types are not available on Windows
161+
}
162+
if (typeof this.mode === 'bigint') { // eslint-disable-line valid-typeof
163+
// eslint-disable-next-line no-undef
164+
return (this.mode & BigInt(S_IFMT)) === BigInt(property);
165+
}
166+
return (this.mode & S_IFMT) === property;
159167
};
160168

161169
Stats.prototype.isDirectory = function() {
@@ -189,9 +197,9 @@ Stats.prototype.isSocket = function() {
189197
function getStatsFromBinding(stats, offset = 0) {
190198
return new Stats(stats[0 + offset], stats[1 + offset], stats[2 + offset],
191199
stats[3 + offset], stats[4 + offset], stats[5 + offset],
192-
stats[6 + offset] < 0 ? undefined : stats[6 + offset],
200+
isWindows ? undefined : stats[6 + offset], // blksize
193201
stats[7 + offset], stats[8 + offset],
194-
stats[9 + offset] < 0 ? undefined : stats[9 + offset],
202+
isWindows ? undefined : stats[9 + offset], // blocks
195203
stats[10 + offset], stats[11 + offset],
196204
stats[12 + offset], stats[13 + offset]);
197205
}

lib/internal/fs/watchers.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ function emitStop(self) {
2121
self.emit('stop');
2222
}
2323

24-
function StatWatcher() {
24+
function StatWatcher(bigint) {
2525
EventEmitter.call(this);
2626

27-
this._handle = new _StatWatcher();
27+
this._handle = new _StatWatcher(bigint);
2828

2929
// uv_fs_poll is a little more powerful than ev_stat but we curb it for
3030
// the sake of backwards compatibility

src/env-inl.h

+5
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,11 @@ Environment::fs_stats_field_array() {
546546
return &fs_stats_field_array_;
547547
}
548548

549+
inline AliasedBuffer<uint64_t, v8::BigUint64Array>*
550+
Environment::fs_stats_field_bigint_array() {
551+
return &fs_stats_field_bigint_array_;
552+
}
553+
549554
inline std::vector<std::unique_ptr<fs::FileHandleReadWrap>>&
550555
Environment::file_handle_read_wrap_freelist() {
551556
return file_handle_read_wrap_freelist_;

src/env.cc

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ Environment::Environment(IsolateData* isolate_data,
116116
#endif
117117
http_parser_buffer_(nullptr),
118118
fs_stats_field_array_(isolate_, kFsStatsFieldsLength * 2),
119+
fs_stats_field_bigint_array_(isolate_, kFsStatsFieldsLength * 2),
119120
context_(context->GetIsolate(), context) {
120121
// We'll be creating new objects so make sure we've entered the context.
121122
v8::HandleScope handle_scope(isolate());

src/env.h

+3
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,8 @@ class Environment {
694694
void set_debug_categories(const std::string& cats, bool enabled);
695695

696696
inline AliasedBuffer<double, v8::Float64Array>* fs_stats_field_array();
697+
inline AliasedBuffer<uint64_t, v8::BigUint64Array>*
698+
fs_stats_field_bigint_array();
697699

698700
// stat fields contains twice the number of entries because `fs.StatWatcher`
699701
// needs room to store data for *two* `fs.Stats` instances.
@@ -914,6 +916,7 @@ class Environment {
914916
bool debug_enabled_[static_cast<int>(DebugCategory::CATEGORY_COUNT)] = {0};
915917

916918
AliasedBuffer<double, v8::Float64Array> fs_stats_field_array_;
919+
AliasedBuffer<uint64_t, v8::BigUint64Array> fs_stats_field_bigint_array_;
917920

918921
std::vector<std::unique_ptr<fs::FileHandleReadWrap>>
919922
file_handle_read_wrap_freelist_;

0 commit comments

Comments
 (0)