1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
--- 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<uint8_t, v8::Uint8Array> AliasedUint8Array;
typedef AliasedBufferBase<uint32_t, v8::Uint32Array> AliasedUint32Array;
typedef AliasedBufferBase<double, v8::Float64Array> AliasedFloat64Array;
-typedef AliasedBufferBase<int64_t, v8::BigInt64Array> AliasedBigInt64Array;
+typedef AliasedBufferBase<int64_t, v8::BigUint64Array> 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<size_t>(FsStatsOffset::stat_offset), \
static_cast<NativeT>(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<unsigned long>(stat))
-#else
-#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat) \
- SET_FIELD_WITH_STAT(stat_offset, static_cast<double>(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<AliasedBigInt64Array>::New(binding_data, use_bigint);
+ return FSReqPromise<AliasedBigUint64Array>::New(binding_data, use_bigint);
} else {
return FSReqPromise<AliasedFloat64Array>::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<v8::Object> wrap);
AliasedFloat64Array stats_field_array;
- AliasedBigInt64Array stats_field_bigint_array;
+ AliasedBigUint64Array stats_field_bigint_array;
std::vector<BaseObjectPtr<FileHandleReadWrap>>
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
-}
|