Skip to content

Commit 5579bc8

Browse files
refackaddaleax
authored andcommitted
src,fs: calculate times as unsigned long
PR-URL: #13281 Fixes: #13255 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 84b1641 commit 5579bc8

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

src/node_file.cc

+7-4
Original file line numberDiff line numberDiff line change
@@ -478,10 +478,13 @@ void FillStatsArray(double* fields, const uv_stat_t* s) {
478478
#else
479479
fields[9] = -1;
480480
#endif
481-
// Dates.
482-
#define X(idx, name) \
483-
fields[idx] = (s->st_##name.tv_sec * 1e3) + \
484-
(s->st_##name.tv_nsec / 1e6); \
481+
// Dates.
482+
// NO-LINT because the fields are 'long' and we just want to cast to `unsigned`
483+
#define X(idx, name) \
484+
/* NOLINTNEXTLINE(runtime/int) */ \
485+
fields[idx] = ((unsigned long)(s->st_##name.tv_sec) * 1e3) + \
486+
/* NOLINTNEXTLINE(runtime/int) */ \
487+
((unsigned long)(s->st_##name.tv_nsec) / 1e6); \
485488

486489
X(10, atim)
487490
X(11, mtim)

test/parallel/test-fs-utimes.js

+34-2
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,40 @@ runTest(new Date('1982-09-10 13:37'), new Date('1982-09-10 13:37'), function() {
163163
});
164164
});
165165

166-
167166
process.on('exit', function() {
168-
console.log('Tests run / ok:', tests_run, '/', tests_ok);
169167
assert.strictEqual(tests_ok, tests_run);
170168
});
169+
170+
171+
// Ref: https://github.com/nodejs/node/issues/13255
172+
common.refreshTmpDir();
173+
const path = `${common.tmpDir}/test-utimes-precision`;
174+
fs.writeFileSync(path, '');
175+
176+
// test Y2K38 for all platforms [except 'arm', and 'SunOS']
177+
if (!process.arch.includes('arm') && !common.isSunOS) {
178+
// because 2 ** 31 doesn't look right
179+
// eslint-disable-next-line space-infix-ops
180+
const Y2K38_mtime = 2**31;
181+
fs.utimesSync(path, Y2K38_mtime, Y2K38_mtime);
182+
const Y2K38_stats = fs.statSync(path);
183+
assert.strictEqual(Y2K38_mtime, Y2K38_stats.mtime.getTime() / 1000);
184+
}
185+
186+
if (common.isWindows) {
187+
// this value would get converted to (double)1713037251359.9998
188+
const truncate_mtime = 1713037251360;
189+
fs.utimesSync(path, truncate_mtime / 1000, truncate_mtime / 1000);
190+
const truncate_stats = fs.statSync(path);
191+
assert.strictEqual(truncate_mtime, truncate_stats.mtime.getTime());
192+
193+
// test Y2K38 for windows
194+
// This value if treaded as a `signed long` gets converted to -2135622133469.
195+
// POSIX systems stores timestamps in {long t_sec, long t_usec}.
196+
// NTFS stores times in nanoseconds in a single `uint64_t`, so when libuv
197+
// calculates (long)`uv_timespec_t.tv_sec` we get 2's complement.
198+
const overflow_mtime = 2159345162531;
199+
fs.utimesSync(path, overflow_mtime / 1000, overflow_mtime / 1000);
200+
const overflow_stats = fs.statSync(path);
201+
assert.strictEqual(overflow_mtime, overflow_stats.mtime.getTime());
202+
}

0 commit comments

Comments
 (0)