diff options
author | Joyee Cheung <joyeec9h3@gmail.com> | 2018-06-19 02:58:49 +0800 |
---|---|---|
committer | Joyee Cheung <joyeec9h3@gmail.com> | 2019-06-14 03:24:41 +0800 |
commit | b245257b70750bdc52a8c315de4b10965dacfed6 (patch) | |
tree | 004c92ceffe5f568ec5d06b592aaa38b157c80fe | |
parent | 4b1bcae681e209984604341f2acfe722345b1b23 (diff) | |
download | android-node-v8-b245257b70750bdc52a8c315de4b10965dacfed6.tar.gz android-node-v8-b245257b70750bdc52a8c315de4b10965dacfed6.tar.bz2 android-node-v8-b245257b70750bdc52a8c315de4b10965dacfed6.zip |
fs: add *timeNs properties to BigInt Stats objects
- Extend the aliased buffer for stats objects to contain
the entire time spec (seconds and nanoseconds) for the time
values instead of calculating the milliseconds in C++ and
lose precision there.
- Calculate the nanosecond-precision time values in JS and expose
them in BigInt Stats objects as `*timeNs`. The
millisecond-precision values are now calculated from the
nanosecond-precision values.
PR-URL: https://github.com/nodejs/node/pull/21387
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gus Caplan <me@gus.host>
-rw-r--r-- | doc/api/fs.md | 71 | ||||
-rw-r--r-- | lib/internal/fs/utils.js | 163 | ||||
-rw-r--r-- | src/env.h | 26 | ||||
-rw-r--r-- | src/node_file.cc | 11 | ||||
-rw-r--r-- | src/node_file.h | 95 | ||||
-rw-r--r-- | test/parallel/test-fs-stat-bigint.js | 20 | ||||
-rw-r--r-- | test/parallel/test-fs-watchfile-bigint.js | 18 |
7 files changed, 275 insertions, 129 deletions
diff --git a/doc/api/fs.md b/doc/api/fs.md index f1b7e1ccbb..1c3742903a 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -512,7 +512,8 @@ A `fs.Stats` object provides information about a file. Objects returned from [`fs.stat()`][], [`fs.lstat()`][] and [`fs.fstat()`][] and their synchronous counterparts are of this type. If `bigint` in the `options` passed to those methods is true, the numeric values -will be `bigint` instead of `number`. +will be `bigint` instead of `number`, and the object will contain additional +nanosecond-precision properties suffixed with `Ns`. ```console Stats { @@ -539,7 +540,7 @@ Stats { `bigint` version: ```console -Stats { +BigIntStats { dev: 2114n, ino: 48064969n, mode: 33188n, @@ -554,6 +555,10 @@ Stats { mtimeMs: 1318289051000n, ctimeMs: 1318289051000n, birthtimeMs: 1318289051000n, + atimeNs: 1318289051000000000n, + mtimeNs: 1318289051000000000n, + ctimeNs: 1318289051000000000n, + birthtimeNs: 1318289051000000000n, atime: Mon, 10 Oct 2011 23:24:11 GMT, mtime: Mon, 10 Oct 2011 23:24:11 GMT, ctime: Mon, 10 Oct 2011 23:24:11 GMT, @@ -726,6 +731,54 @@ added: v8.1.0 The timestamp indicating the creation time of this file expressed in milliseconds since the POSIX Epoch. +### stats.atimeNs +<!-- YAML +added: REPLACEME +--> + +* {bigint} + +Only present when `bigint: true` is passed into the method that generates +the object. +The timestamp indicating the last time this file was accessed expressed in +nanoseconds since the POSIX Epoch. + +### stats.mtimeNs +<!-- YAML +added: REPLACEME +--> + +* {bigint} + +Only present when `bigint: true` is passed into the method that generates +the object. +The timestamp indicating the last time this file was modified expressed in +nanoseconds since the POSIX Epoch. + +### stats.ctimeNs +<!-- YAML +added: REPLACEME +--> + +* {bigint} + +Only present when `bigint: true` is passed into the method that generates +the object. +The timestamp indicating the last time the file status was changed expressed +in nanoseconds since the POSIX Epoch. + +### stats.birthtimeNs +<!-- YAML +added: REPLACEME +--> + +* {bigint} + +Only present when `bigint: true` is passed into the method that generates +the object. +The timestamp indicating the creation time of this file expressed in +nanoseconds since the POSIX Epoch. + ### stats.atime <!-- YAML added: v0.11.13 @@ -765,8 +818,17 @@ The timestamp indicating the creation time of this file. ### Stat Time Values The `atimeMs`, `mtimeMs`, `ctimeMs`, `birthtimeMs` properties are -[numbers][MDN-Number] that hold the corresponding times in milliseconds. Their -precision is platform specific. `atime`, `mtime`, `ctime`, and `birthtime` are +numeric values that hold the corresponding times in milliseconds. Their +precision is platform specific. When `bigint: true` is passed into the +method that generates the object, the properties will be [bigints][], +otherwise they will be [numbers][MDN-Number]. + +The `atimeNs`, `mtimeNs`, `ctimeNs`, `birthtimeNs` properties are +[bigints][] that hold the corresponding times in nanoseconds. They are +only present when `bigint: true` is passed into the method that generates +the object. Their precision is platform specific. + +`atime`, `mtime`, `ctime`, and `birthtime` are [`Date`][MDN-Date] object alternate representations of the various times. The `Date` and number values are not connected. Assigning a new number value, or mutating the `Date` value, will not be reflected in the corresponding alternate @@ -4976,6 +5038,7 @@ the file contents. [`net.Socket`]: net.html#net_class_net_socket [`stat()`]: fs.html#fs_fs_stat_path_options_callback [`util.promisify()`]: util.html#util_util_promisify_original +[bigints]: https://tc39.github.io/proposal-bigint [Caveats]: #fs_caveats [Common System Errors]: errors.html#errors_common_system_errors [FS Constants]: #fs_fs_constants_1 diff --git a/lib/internal/fs/utils.js b/lib/internal/fs/utils.js index 14abad81ec..6cd6f7aceb 100644 --- a/lib/internal/fs/utils.js +++ b/lib/internal/fs/utils.js @@ -1,6 +1,6 @@ 'use strict'; -const { Reflect } = primordials; +const { Object, Reflect } = primordials; const { Buffer, kMaxLength } = require('buffer'); const { @@ -16,7 +16,8 @@ const { } = require('internal/errors'); const { isUint8Array, - isDate + isDate, + isBigUint64Array } = require('internal/util/types'); const { once } = require('internal/util'); const { toPathIfFileURL } = require('internal/url'); @@ -230,27 +231,9 @@ function preprocessSymlinkDestination(path, type, linkPath) { } } -function dateFromNumeric(num) { - return new Date(Number(num) + 0.5); -} - // Constructor for file stats. -function Stats( - dev, - mode, - nlink, - uid, - gid, - rdev, - blksize, - ino, - size, - blocks, - atim_msec, - mtim_msec, - ctim_msec, - birthtim_msec -) { +function StatsBase(dev, mode, nlink, uid, gid, rdev, blksize, + ino, size, blocks) { this.dev = dev; this.mode = mode; this.nlink = nlink; @@ -261,63 +244,132 @@ function Stats( this.ino = ino; this.size = size; this.blocks = blocks; - this.atimeMs = atim_msec; - this.mtimeMs = mtim_msec; - this.ctimeMs = ctim_msec; - this.birthtimeMs = birthtim_msec; - this.atime = dateFromNumeric(atim_msec); - this.mtime = dateFromNumeric(mtim_msec); - this.ctime = dateFromNumeric(ctim_msec); - this.birthtime = dateFromNumeric(birthtim_msec); } -Stats.prototype._checkModeProperty = function(property) { - if (isWindows && (property === S_IFIFO || property === S_IFBLK || - property === S_IFSOCK)) { - return false; // Some types are not available on Windows - } - if (typeof this.mode === 'bigint') { // eslint-disable-line valid-typeof - return (this.mode & BigInt(S_IFMT)) === BigInt(property); - } - return (this.mode & S_IFMT) === property; -}; - -Stats.prototype.isDirectory = function() { +StatsBase.prototype.isDirectory = function() { return this._checkModeProperty(S_IFDIR); }; -Stats.prototype.isFile = function() { +StatsBase.prototype.isFile = function() { return this._checkModeProperty(S_IFREG); }; -Stats.prototype.isBlockDevice = function() { +StatsBase.prototype.isBlockDevice = function() { return this._checkModeProperty(S_IFBLK); }; -Stats.prototype.isCharacterDevice = function() { +StatsBase.prototype.isCharacterDevice = function() { return this._checkModeProperty(S_IFCHR); }; -Stats.prototype.isSymbolicLink = function() { +StatsBase.prototype.isSymbolicLink = function() { return this._checkModeProperty(S_IFLNK); }; -Stats.prototype.isFIFO = function() { +StatsBase.prototype.isFIFO = function() { return this._checkModeProperty(S_IFIFO); }; -Stats.prototype.isSocket = function() { +StatsBase.prototype.isSocket = function() { return this._checkModeProperty(S_IFSOCK); }; +const kNsPerMsBigInt = 10n ** 6n; +const kNsPerSecBigInt = 10n ** 9n; +const kMsPerSec = 10 ** 3; +const kNsPerMs = 10 ** 6; +function msFromTimeSpec(sec, nsec) { + return sec * kMsPerSec + nsec / kNsPerMs; +} + +function nsFromTimeSpecBigInt(sec, nsec) { + return sec * kNsPerSecBigInt + nsec; +} + +function dateFromMs(ms) { + return new Date(Number(ms) + 0.5); +} + +function BigIntStats(dev, mode, nlink, uid, gid, rdev, blksize, + ino, size, blocks, + atimeNs, mtimeNs, ctimeNs, birthtimeNs) { + StatsBase.call(this, dev, mode, nlink, uid, gid, rdev, blksize, + ino, size, blocks); + + this.atimeMs = atimeNs / kNsPerMsBigInt; + this.mtimeMs = mtimeNs / kNsPerMsBigInt; + this.ctimeMs = ctimeNs / kNsPerMsBigInt; + this.birthtimeMs = birthtimeNs / kNsPerMsBigInt; + this.atimeNs = atimeNs; + this.mtimeNs = mtimeNs; + this.ctimeNs = ctimeNs; + this.birthtimeNs = birthtimeNs; + this.atime = dateFromMs(this.atimeMs); + this.mtime = dateFromMs(this.mtimeMs); + this.ctime = dateFromMs(this.ctimeMs); + this.birthtime = dateFromMs(this.birthtimeMs); +} + +Object.setPrototypeOf(BigIntStats.prototype, StatsBase.prototype); +Object.setPrototypeOf(BigIntStats, StatsBase); + +BigIntStats.prototype._checkModeProperty = function(property) { + if (isWindows && (property === S_IFIFO || property === S_IFBLK || + property === S_IFSOCK)) { + return false; // Some types are not available on Windows + } + return (this.mode & BigInt(S_IFMT)) === BigInt(property); +}; + +function Stats(dev, mode, nlink, uid, gid, rdev, blksize, + ino, size, blocks, + atimeMs, mtimeMs, ctimeMs, birthtimeMs) { + StatsBase.call(this, dev, mode, nlink, uid, gid, rdev, blksize, + ino, size, blocks); + this.atimeMs = atimeMs; + this.mtimeMs = mtimeMs; + this.ctimeMs = ctimeMs; + this.birthtimeMs = birthtimeMs; + this.atime = dateFromMs(atimeMs); + this.mtime = dateFromMs(mtimeMs); + this.ctime = dateFromMs(ctimeMs); + this.birthtime = dateFromMs(birthtimeMs); +} + +Object.setPrototypeOf(Stats.prototype, StatsBase.prototype); +Object.setPrototypeOf(Stats, StatsBase); + +Stats.prototype._checkModeProperty = function(property) { + if (isWindows && (property === S_IFIFO || property === S_IFBLK || + property === S_IFSOCK)) { + return false; // Some types are not available on Windows + } + return (this.mode & S_IFMT) === property; +}; + function getStatsFromBinding(stats, offset = 0) { - return new Stats(stats[0 + offset], stats[1 + offset], stats[2 + offset], - stats[3 + offset], stats[4 + offset], stats[5 + offset], - stats[6 + offset], // blksize - stats[7 + offset], stats[8 + offset], - stats[9 + offset], // blocks - stats[10 + offset], stats[11 + offset], - stats[12 + offset], stats[13 + offset]); + if (isBigUint64Array(stats)) { + return new BigIntStats( + stats[0 + offset], stats[1 + offset], stats[2 + offset], + stats[3 + offset], stats[4 + offset], stats[5 + offset], + stats[6 + offset], stats[7 + offset], stats[8 + offset], + stats[9 + offset], + nsFromTimeSpecBigInt(stats[10 + offset], stats[11 + offset]), + nsFromTimeSpecBigInt(stats[12 + offset], stats[13 + offset]), + nsFromTimeSpecBigInt(stats[14 + offset], stats[15 + offset]), + nsFromTimeSpecBigInt(stats[16 + offset], stats[17 + offset]) + ); + } + return new Stats( + stats[0 + offset], stats[1 + offset], stats[2 + offset], + stats[3 + offset], stats[4 + offset], stats[5 + offset], + stats[6 + offset], stats[7 + offset], stats[8 + offset], + stats[9 + offset], + msFromTimeSpec(stats[10 + offset], stats[11 + offset]), + msFromTimeSpec(stats[12 + offset], stats[13 + offset]), + msFromTimeSpec(stats[14 + offset], stats[15 + offset]), + msFromTimeSpec(stats[16 + offset], stats[17 + offset]) + ); } function stringToFlags(flags) { @@ -453,6 +505,7 @@ function warnOnNonPortableTemplate(template) { module.exports = { assertEncoding, + BigIntStats, // for testing copyObject, Dirent, getDirents, @@ -102,10 +102,32 @@ struct PackageConfig { }; } // namespace loader +enum class FsStatsOffset { + kDev = 0, + kMode, + kNlink, + kUid, + kGid, + kRdev, + kBlkSize, + kIno, + kSize, + kBlocks, + kATimeSec, + kATimeNsec, + kMTimeSec, + kMTimeNsec, + kCTimeSec, + kCTimeNsec, + kBirthTimeSec, + kBirthTimeNsec, + kFsStatsFieldsNumber +}; + // Stat fields buffers contain twice the number of entries in an uv_stat_t // because `fs.StatWatcher` needs room to store 2 `fs.Stats` instances. -constexpr size_t kFsStatsFieldsNumber = 14; -constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2; +constexpr size_t kFsStatsBufferLength = + static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber) * 2; // PER_ISOLATE_* macros: We have a lot of per-isolate properties // and adding and maintaining their getters and setters by hand would be diff --git a/src/node_file.cc b/src/node_file.cc index 8f82d639d6..564c63bad7 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -2197,10 +2197,13 @@ void Initialize(Local<Object> target, env->SetMethod(target, "mkdtemp", Mkdtemp); - target->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"), - Integer::New(isolate, kFsStatsFieldsNumber)) - .Check(); + target + ->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"), + Integer::New( + isolate, + static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber))) + .Check(); target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "statValues"), diff --git a/src/node_file.h b/src/node_file.h index ae50a50b38..2ea5af025d 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -6,6 +6,7 @@ #include "node.h" #include "stream_base.h" #include "req_wrap-inl.h" +#include <iostream> namespace node { @@ -149,74 +150,48 @@ class FSReqCallback : public FSReqBase { FSReqCallback& operator=(const FSReqCallback&) = delete; }; -// Wordaround a GCC4.9 bug that C++14 N3652 was not implemented -// Refs: https://www.gnu.org/software/gcc/projects/cxx-status.html#cxx14 -// Refs: https://isocpp.org/files/papers/N3652.html -#if __cpp_constexpr < 201304 -# define constexpr inline -#endif - -template <typename NativeT, - // SFINAE limit NativeT to arithmetic types - typename = std::enable_if<std::is_arithmetic<NativeT>::value>> -constexpr NativeT ToNative(uv_timespec_t ts) { - // This template has exactly two specializations below. - static_assert(std::is_arithmetic<NativeT>::value == false, "Not implemented"); - return NativeT(); -} - -template <> -constexpr double ToNative(uv_timespec_t ts) { - // We need to do a static_cast since the original FS values are ulong. - /* NOLINTNEXTLINE(runtime/int) */ - const auto u_sec = static_cast<unsigned long>(ts.tv_sec); - const double full_sec = u_sec * 1000.0; - /* NOLINTNEXTLINE(runtime/int) */ - const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec); - const double full_nsec = u_nsec / 1000'000.0; - return full_sec + full_nsec; -} - -template <> -constexpr uint64_t ToNative(uv_timespec_t ts) { - // We need to do a static_cast since the original FS values are ulong. - /* NOLINTNEXTLINE(runtime/int) */ - const auto u_sec = static_cast<unsigned long>(ts.tv_sec); - const auto full_sec = static_cast<uint64_t>(u_sec) * 1000UL; - /* NOLINTNEXTLINE(runtime/int) */ - const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec); - const auto full_nsec = static_cast<uint64_t>(u_nsec) / 1000'000UL; - return full_sec + full_nsec; -} - -#undef constexpr // end N3652 bug workaround - template <typename NativeT, typename V8T> constexpr void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields, const uv_stat_t* s, const size_t offset = 0) { - fields->SetValue(offset + 0, static_cast<NativeT>(s->st_dev)); - fields->SetValue(offset + 1, static_cast<NativeT>(s->st_mode)); - fields->SetValue(offset + 2, static_cast<NativeT>(s->st_nlink)); - fields->SetValue(offset + 3, static_cast<NativeT>(s->st_uid)); - fields->SetValue(offset + 4, static_cast<NativeT>(s->st_gid)); - fields->SetValue(offset + 5, static_cast<NativeT>(s->st_rdev)); - fields->SetValue(offset + 6, static_cast<NativeT>(s->st_blksize)); - fields->SetValue(offset + 7, static_cast<NativeT>(s->st_ino)); - fields->SetValue(offset + 8, static_cast<NativeT>(s->st_size)); - fields->SetValue(offset + 9, static_cast<NativeT>(s->st_blocks)); -// Dates. - fields->SetValue(offset + 10, ToNative<NativeT>(s->st_atim)); - fields->SetValue(offset + 11, ToNative<NativeT>(s->st_mtim)); - fields->SetValue(offset + 12, ToNative<NativeT>(s->st_ctim)); - fields->SetValue(offset + 13, ToNative<NativeT>(s->st_birthtim)); +#define SET_FIELD_WITH_STAT(stat_offset, stat) \ + fields->SetValue(offset + static_cast<size_t>(FsStatsOffset::stat_offset), \ + static_cast<NativeT>(stat)) + +#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat) \ + /* NOLINTNEXTLINE(runtime/int) */ \ + SET_FIELD_WITH_STAT(stat_offset, static_cast<unsigned long>(stat)) + + SET_FIELD_WITH_STAT(kDev, s->st_dev); + SET_FIELD_WITH_STAT(kMode, s->st_mode); + SET_FIELD_WITH_STAT(kNlink, s->st_nlink); + SET_FIELD_WITH_STAT(kUid, s->st_uid); + SET_FIELD_WITH_STAT(kGid, s->st_gid); + SET_FIELD_WITH_STAT(kRdev, s->st_rdev); + SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize); + SET_FIELD_WITH_STAT(kIno, s->st_ino); + SET_FIELD_WITH_STAT(kSize, s->st_size); + SET_FIELD_WITH_STAT(kBlocks, s->st_blocks); + + SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec); + SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec); + SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec); + SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec); + SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec); + SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec); + SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec); + SET_FIELD_WITH_TIME_STAT(kBirthTimeNsec, s->st_birthtim.tv_nsec); + +#undef SET_FIELD_WITH_TIME_STAT +#undef SET_FIELD_WITH_STAT } inline Local<Value> FillGlobalStatsArray(Environment* env, const bool use_bigint, const uv_stat_t* s, const bool second = false) { - const ptrdiff_t offset = second ? kFsStatsFieldsNumber : 0; + const ptrdiff_t offset = + second ? static_cast<ptrdiff_t>(FsStatsOffset::kFsStatsFieldsNumber) : 0; if (use_bigint) { auto* const arr = env->fs_stats_field_bigint_array(); FillStatsArray(arr, s, offset); @@ -302,7 +277,9 @@ class FSReqPromise : public FSReqBase { private: FSReqPromise(Environment* env, v8::Local<v8::Object> obj, bool use_bigint) : FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint), - stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {} + stats_field_array_( + env->isolate(), + static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {} bool finished_ = false; AliasedBufferT stats_field_array_; diff --git a/test/parallel/test-fs-stat-bigint.js b/test/parallel/test-fs-stat-bigint.js index d004112680..998ddb289d 100644 --- a/test/parallel/test-fs-stat-bigint.js +++ b/test/parallel/test-fs-stat-bigint.js @@ -59,6 +59,26 @@ function verifyStats(bigintStats, numStats) { bigintStats.isSymbolicLink(), numStats.isSymbolicLink() ); + } else if (key.endsWith('Ms')) { + const nsKey = key.replace('Ms', 'Ns'); + const msFromBigInt = bigintStats[key]; + const nsFromBigInt = bigintStats[nsKey]; + const msFromBigIntNs = Number(nsFromBigInt / (10n ** 6n)); + const msFromNum = numStats[key]; + // The difference between the millisecond-precision values should be + // smaller than 2 + assert( + Math.abs(msFromNum - Number(msFromBigInt)) < 2, + `Number version ${key} = ${msFromNum}, ` + + `BigInt version ${key} = ${msFromBigInt}n`); + // The difference between the millisecond-precision value and the + // nanosecond-precision value scaled down to milliseconds should be + // smaller than 2 + assert( + Math.abs(msFromNum - Number(msFromBigIntNs)) < 2, + `Number version ${key} = ${msFromNum}, ` + + `BigInt version ${nsKey} = ${nsFromBigInt}n` + + ` = ${msFromBigIntNs}ms`); } else if (Number.isSafeInteger(val)) { assert.strictEqual( bigintStats[key], BigInt(val), diff --git a/test/parallel/test-fs-watchfile-bigint.js b/test/parallel/test-fs-watchfile-bigint.js index d5528bb2d3..500a0ef1f6 100644 --- a/test/parallel/test-fs-watchfile-bigint.js +++ b/test/parallel/test-fs-watchfile-bigint.js @@ -1,14 +1,18 @@ 'use strict'; + +// Flags: --expose-internals + const common = require('../common'); const assert = require('assert'); +const { BigIntStats } = require('internal/fs/utils'); const fs = require('fs'); const path = require('path'); const tmpdir = require('../common/tmpdir'); const enoentFile = path.join(tmpdir.path, 'non-existent-file'); -const expectedStatObject = new fs.Stats( +const expectedStatObject = new BigIntStats( 0n, // dev 0n, // mode 0n, // nlink @@ -19,10 +23,14 @@ const expectedStatObject = new fs.Stats( 0n, // ino 0n, // size 0n, // blocks - 0n, // atim_msec - 0n, // mtim_msec - 0n, // ctim_msec - 0n // birthtim_msec + 0n, // atimeMs + 0n, // mtimeMs + 0n, // ctimeMs + 0n, // birthtimeMs + 0n, // atimeNs + 0n, // mtimeNs + 0n, // ctimeNs + 0n // birthtimeNs ); tmpdir.refresh(); |