--- node-v18.12.1/lib/internal/fs/utils.js.old 2022-11-04 11:13:14.000000000 -0500 +++ node-v18.12.1/lib/internal/fs/utils.js 2023-01-01 18:07:20.292441829 -0600 @@ -12,7 +12,6 @@ NumberIsFinite, NumberIsInteger, MathMin, - MathRound, ObjectIs, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, @@ -40,7 +39,7 @@ } = require('internal/errors'); const { isArrayBufferView, - isBigInt64Array, + isBigUint64Array, isDate, isUint8Array, } = require('internal/util/types'); @@ -455,16 +454,14 @@ return sec * kNsPerSecBigInt + nsec; } -// The Date constructor performs Math.floor() on the absolute value -// of the timestamp: https://tc39.es/ecma262/#sec-timeclip +// The Date constructor performs Math.floor() to the timestamp. +// https://tc39.es/ecma262/#sec-timeclip // Since there may be a precision loss when the timestamp is // converted to a floating point number, we manually round // the timestamp here before passing it to Date(). // Refs: https://github.com/nodejs/node/pull/12607 -// Refs: https://github.com/nodejs/node/pull/43714 function dateFromMs(ms) { - // Coercing to number, ms can be bigint - return new Date(MathRound(Number(ms))); + return new Date(Number(ms) + 0.5); } function BigIntStats(dev, mode, nlink, uid, gid, rdev, blksize, @@ -529,12 +526,12 @@ }; /** - * @param {Float64Array | BigInt64Array} stats + * @param {Float64Array | BigUint64Array} stats * @param {number} offset * @returns {BigIntStats | Stats} */ function getStatsFromBinding(stats, offset = 0) { - if (isBigInt64Array(stats)) { + if (isBigUint64Array(stats)) { return new BigIntStats( stats[0 + offset], stats[1 + offset], stats[2 + offset], stats[3 + offset], stats[4 + offset], stats[5 + offset], --- node-v18.12.1/src/aliased_buffer.h.old 2022-11-04 11:13:14.000000000 -0500 +++ node-v18.12.1/src/aliased_buffer.h 2023-01-01 18:08:01.407999936 -0600 @@ -306,7 +306,7 @@ typedef AliasedBufferBase AliasedUint8Array; typedef AliasedBufferBase AliasedUint32Array; typedef AliasedBufferBase AliasedFloat64Array; -typedef AliasedBufferBase AliasedBigInt64Array; +typedef AliasedBufferBase AliasedBigUint64Array; } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS --- node-v18.12.1/src/node_file-inl.h.old 2022-11-04 11:13:14.000000000 -0500 +++ node-v18.12.1/src/node_file-inl.h 2023-01-01 18:09:07.830823990 -0600 @@ -90,18 +90,9 @@ fields->SetValue(offset + static_cast(FsStatsOffset::stat_offset), \ static_cast(stat)) -// On win32, time is stored in uint64_t and starts from 1601-01-01. -// libuv calculates tv_sec and tv_nsec from it and converts to signed long, -// which causes Y2038 overflow. On the other platforms it is safe to treat -// negative values as pre-epoch time. -#ifdef _WIN32 #define SET_FIELD_WITH_TIME_STAT(stat_offset, stat) \ /* NOLINTNEXTLINE(runtime/int) */ \ SET_FIELD_WITH_STAT(stat_offset, static_cast(stat)) -#else -#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat) \ - SET_FIELD_WITH_STAT(stat_offset, static_cast(stat)) -#endif // _WIN32 SET_FIELD_WITH_STAT(kDev, s->st_dev); SET_FIELD_WITH_STAT(kMode, s->st_mode); @@ -242,7 +233,7 @@ Environment* env = binding_data->env(); if (value->StrictEquals(env->fs_use_promises_symbol())) { if (use_bigint) { - return FSReqPromise::New(binding_data, use_bigint); + return FSReqPromise::New(binding_data, use_bigint); } else { return FSReqPromise::New(binding_data, use_bigint); } --- node-v18.12.1/src/node_file.h.old 2022-11-04 11:13:14.000000000 -0500 +++ node-v18.12.1/src/node_file.h 2023-01-01 18:09:24.888981123 -0600 @@ -18,7 +18,7 @@ explicit BindingData(Environment* env, v8::Local wrap); AliasedFloat64Array stats_field_array; - AliasedBigInt64Array stats_field_bigint_array; + AliasedBigUint64Array stats_field_bigint_array; std::vector> file_handle_read_wrap_freelist; --- node-v18.12.1/test/parallel/test-fs-stat-date.mjs.old 2022-11-04 11:13:14.000000000 -0500 +++ node-v18.12.1/test/parallel/test-fs-stat-date.mjs 1969-12-31 18:00:00.000000000 -0600 @@ -1,95 +0,0 @@ -import * as common from '../common/index.mjs'; - -// Test timestamps returned by fsPromises.stat and fs.statSync - -import fs from 'node:fs'; -import fsPromises from 'node:fs/promises'; -import path from 'node:path'; -import assert from 'node:assert'; -import tmpdir from '../common/tmpdir.js'; - -// On some platforms (for example, ppc64) boundaries are tighter -// than usual. If we catch these errors, skip corresponding test. -const ignoredErrors = new Set(['EINVAL', 'EOVERFLOW']); - -tmpdir.refresh(); -const filepath = path.resolve(tmpdir.path, 'timestamp'); - -await (await fsPromises.open(filepath, 'w')).close(); - -// Perform a trivial check to determine if filesystem supports setting -// and retrieving atime and mtime. If it doesn't, skip the test. -await fsPromises.utimes(filepath, 2, 2); -const { atimeMs, mtimeMs } = await fsPromises.stat(filepath); -if (atimeMs !== 2000 || mtimeMs !== 2000) { - common.skip(`Unsupported filesystem (atime=${atimeMs}, mtime=${mtimeMs})`); -} - -// Date might round down timestamp -function closeEnough(actual, expected, margin) { - // On ppc64, value is rounded to seconds - if (process.arch === 'ppc64') { - margin += 1000; - } - - // Filesystems without support for timestamps before 1970-01-01, such as NFSv3, - // should return 0 for negative numbers. Do not treat it as error. - if (actual === 0 && expected < 0) { - console.log(`ignored 0 while expecting ${expected}`); - return; - } - - assert.ok(Math.abs(Number(actual - expected)) < margin, - `expected ${expected} ± ${margin}, got ${actual}`); -} - -async function runTest(atime, mtime, margin = 0) { - margin += Number.EPSILON; - try { - await fsPromises.utimes(filepath, new Date(atime), new Date(mtime)); - } catch (e) { - if (ignoredErrors.has(e.code)) return; - throw e; - } - - const stats = await fsPromises.stat(filepath); - closeEnough(stats.atimeMs, atime, margin); - closeEnough(stats.mtimeMs, mtime, margin); - closeEnough(stats.atime.getTime(), new Date(atime).getTime(), margin); - closeEnough(stats.mtime.getTime(), new Date(mtime).getTime(), margin); - - const statsBigint = await fsPromises.stat(filepath, { bigint: true }); - closeEnough(statsBigint.atimeMs, BigInt(atime), margin); - closeEnough(statsBigint.mtimeMs, BigInt(mtime), margin); - closeEnough(statsBigint.atime.getTime(), new Date(atime).getTime(), margin); - closeEnough(statsBigint.mtime.getTime(), new Date(mtime).getTime(), margin); - - const statsSync = fs.statSync(filepath); - closeEnough(statsSync.atimeMs, atime, margin); - closeEnough(statsSync.mtimeMs, mtime, margin); - closeEnough(statsSync.atime.getTime(), new Date(atime).getTime(), margin); - closeEnough(statsSync.mtime.getTime(), new Date(mtime).getTime(), margin); - - const statsSyncBigint = fs.statSync(filepath, { bigint: true }); - closeEnough(statsSyncBigint.atimeMs, BigInt(atime), margin); - closeEnough(statsSyncBigint.mtimeMs, BigInt(mtime), margin); - closeEnough(statsSyncBigint.atime.getTime(), new Date(atime).getTime(), margin); - closeEnough(statsSyncBigint.mtime.getTime(), new Date(mtime).getTime(), margin); -} - -// Too high/low numbers produce too different results on different platforms -{ - // TODO(LiviaMedeiros): investigate outdated stat time on FreeBSD. - // On Windows, filetime is stored and handled differently. Supporting dates - // after Y2038 is preferred over supporting dates before 1970-01-01. - if (!common.isFreeBSD && !common.isWindows) { - await runTest(-40691, -355, 1); // Potential precision loss on 32bit - await runTest(-355, -40691, 1); // Potential precision loss on 32bit - await runTest(-1, -1); - } - await runTest(0, 0); - await runTest(1, 1); - await runTest(355, 40691, 1); // Precision loss on 32bit - await runTest(40691, 355, 1); // Precision loss on 32bit - await runTest(1713037251360, 1713037251360, 1); // Precision loss -} diff -ur a/src/node_file.h b/src/node_file.h --- a/src/node_file.h 2023-03-20 21:33:20.806694666 +0000 +++ b/src/node_file.h 2023-03-20 21:34:14.388701175 +0000 @@ -62,7 +62,7 @@ AliasedBigUint64Array stats_field_bigint_array; AliasedFloat64Array statfs_field_array; - AliasedBigInt64Array statfs_field_bigint_array; + AliasedBigUint64Array statfs_field_bigint_array; std::vector> file_handle_read_wrap_freelist;