Skip to content

Commit a7b10da

Browse files
authored
Fix utime() syscall (#16460)
Fix off by factor 1000: ``FS.utime()`` expects mtime and atime in seconds. ``times == NULL`` is now correctly handled. ``utimes(path, NULL)`` updates atime and mtime to current time. https://nodejs.org/api/fs.html#fsutimespath-atime-mtime-callback Fixes: #16458 Signed-off-by: Christian Heimes <[email protected]>
1 parent 74d6a15 commit a7b10da

File tree

4 files changed

+44
-15
lines changed

4 files changed

+44
-15
lines changed

src/library_noderawfs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ mergeInto(LibraryManager.library, {
8181
}
8282
fs.ftruncateSync.apply(void 0, arguments);
8383
},
84-
utime: function() { fs.utimesSync.apply(void 0, arguments); },
84+
utime: function(path, atime, mtime) { fs.utimesSync(path, atime/1000, mtime/1000); },
8585
open: function(path, flags, mode, suggestFD) {
8686
if (typeof flags == "string") {
8787
flags = VFS.modeStringToFlags(flags)

src/library_syscall.js

+12-7
Original file line numberDiff line numberDiff line change
@@ -1046,13 +1046,18 @@ var SyscallsLibrary = {
10461046
assert(flags === 0);
10471047
#endif
10481048
path = SYSCALLS.calculateAt(dirfd, path, true);
1049-
var seconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_sec, 'i32') }}};
1050-
var nanoseconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
1051-
var atime = (seconds*1000) + (nanoseconds/(1000*1000));
1052-
times += {{{ C_STRUCTS.timespec.__size__ }}};
1053-
seconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_sec, 'i32') }}};
1054-
nanoseconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
1055-
var mtime = (seconds*1000) + (nanoseconds/(1000*1000));
1049+
if (!times) {
1050+
var atime = Date.now();
1051+
var mtime = atime;
1052+
} else {
1053+
var seconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_sec, 'i32') }}};
1054+
var nanoseconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
1055+
atime = (seconds*1000) + (nanoseconds/(1000*1000));
1056+
times += {{{ C_STRUCTS.timespec.__size__ }}};
1057+
seconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_sec, 'i32') }}};
1058+
nanoseconds = {{{ makeGetValue('times', C_STRUCTS.timespec.tv_nsec, 'i32') }}};
1059+
mtime = (seconds*1000) + (nanoseconds/(1000*1000));
1060+
}
10561061
FS.utime(path, atime, mtime);
10571062
return 0;
10581063
},

system/lib/wasmfs/syscalls.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -1006,10 +1006,15 @@ long __syscall_utimensat(int dirFD,
10061006

10071007
// TODO: Set tv_nsec (nanoseconds) as well.
10081008
// TODO: Handle tv_nsec being UTIME_NOW or UTIME_OMIT.
1009-
// TODO: Handle NULL times.
10101009
// TODO: Check for write access to the file (see man page for specifics).
1011-
auto aSeconds = times[0].tv_sec;
1012-
auto mSeconds = times[1].tv_sec;
1010+
time_t aSeconds, mSeconds;
1011+
if (times == NULL) {
1012+
aSeconds = time(NULL);
1013+
mSeconds = aSeconds;
1014+
} else {
1015+
aSeconds = times[0].tv_sec;
1016+
mSeconds = times[1].tv_sec;
1017+
}
10131018

10141019
auto locked = parsed.getFile()->locked();
10151020
locked.setATime(aSeconds);

tests/utime/test_utime.c

+23-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <stdio.h>
1212
#include <stdlib.h>
1313
#include <string.h>
14+
#include <time.h>
1415
#include <unistd.h>
1516
#include <utime.h>
1617
#include <sys/stat.h>
@@ -32,20 +33,38 @@ void test() {
3233
// will fail
3334
struct utimbuf t = {1000000000, 1000000000};
3435

35-
utime("writeable", &t);
36+
errno = 0;
37+
int rv = utime("writeable", &t);
38+
assert(rv == 0);
3639
assert(!errno);
3740
memset(&s, 0, sizeof s);
38-
stat("writeable", &s);
41+
rv = stat("writeable", &s);
42+
assert(rv == 0);
3943
assert(s.st_atime == t.actime);
4044
assert(s.st_mtime == t.modtime);
4145

46+
// NULL sets atime and mtime to current time.
47+
long now = time(NULL);
48+
rv = utime("writeable", NULL);
49+
assert(rv == 0);
50+
memset(&s, 0, sizeof s);
51+
stat("writeable", &s);
52+
assert(s.st_atime == s.st_mtime);
53+
long diff = s.st_atime - now;
54+
if (abs(diff) > 5) {
55+
fprintf(stderr, "st_atime: %li, now: %li, diff: %li\n ", s.st_atime, now, diff);
56+
assert(abs(diff) <= 5);
57+
}
58+
4259
// write permissions aren't checked when setting node
4360
// attributes unless the user uid isn't the owner (so
4461
// therefor, this should work fine)
45-
utime("unwriteable", &t);
62+
rv = utime("unwriteable", &t);
63+
assert(rv == 0);
4664
assert(!errno);
4765
memset(&s, 0, sizeof s);
48-
stat("unwriteable", &s);
66+
rv = stat("unwriteable", &s);
67+
assert(rv == 0);
4968
assert(s.st_atime == t.actime);
5069
assert(s.st_mtime == t.modtime);
5170

0 commit comments

Comments
 (0)