Skip to content

Commit d25f32e

Browse files
authored
WasmFS: Add nanosecond support to WasmFS (#19629)
This PR adds nanosecond support for file times in WasmFS, specifically when used for utime and stat. This PR was separated from #19561
1 parent 21cc30d commit d25f32e

14 files changed

+81
-38
lines changed

system/lib/wasmfs/file.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ Directory::Handle::insertDataFile(const std::string& name, mode_t mode) {
100100
return nullptr;
101101
}
102102
cacheChild(name, child, DCacheKind::Normal);
103-
setMTime(time(NULL));
103+
updateMTime();
104104
return child;
105105
}
106106

@@ -115,7 +115,7 @@ Directory::Handle::insertDirectory(const std::string& name, mode_t mode) {
115115
return nullptr;
116116
}
117117
cacheChild(name, child, DCacheKind::Normal);
118-
setMTime(time(NULL));
118+
updateMTime();
119119
return child;
120120
}
121121

@@ -131,7 +131,7 @@ Directory::Handle::insertSymlink(const std::string& name,
131131
return nullptr;
132132
}
133133
cacheChild(name, child, DCacheKind::Normal);
134-
setMTime(time(NULL));
134+
updateMTime();
135135
return child;
136136
}
137137

@@ -181,9 +181,8 @@ int Directory::Handle::insertMove(const std::string& name,
181181
file->locked().setParent(getDir());
182182

183183
// TODO: Moving mount points probably shouldn't update the mtime.
184-
auto now = time(NULL);
185-
oldParent->locked().setMTime(now);
186-
setMTime(now);
184+
oldParent->locked().updateMTime();
185+
updateMTime();
187186

188187
return 0;
189188
}
@@ -204,7 +203,7 @@ int Directory::Handle::removeChild(const std::string& name) {
204203
entry->second.file->locked().setParent(nullptr);
205204
dcache.erase(entry);
206205
}
207-
setMTime(time(NULL));
206+
updateMTime();
208207
return 0;
209208
}
210209

system/lib/wasmfs/file.h

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <variant>
2020
#include <vector>
2121
#include <wasi/api.h>
22+
#include <time.h>
2223

2324
namespace wasmfs {
2425

@@ -96,7 +97,9 @@ class File : public std::enable_shared_from_this<File> {
9697
protected:
9798
File(FileKind kind, mode_t mode, backend_t backend)
9899
: kind(kind), mode(mode), backend(backend) {
99-
atime = mtime = ctime = time(NULL);
100+
struct timespec ts;
101+
clock_gettime(CLOCK_REALTIME, &ts);
102+
atime = mtime = ctime = ts;
100103
}
101104

102105
// A mutex is needed for multiple accesses to the same file.
@@ -108,9 +111,9 @@ class File : public std::enable_shared_from_this<File> {
108111

109112
mode_t mode = 0; // User and group mode bits for access permission.
110113

111-
time_t atime = 0; // Time when the content was last accessed.
112-
time_t mtime = 0; // Time when the file content was last modified.
113-
time_t ctime = 0; // Time when the file node was last modified.
114+
struct timespec atime; // Time when the content was last accessed.
115+
struct timespec mtime; // Time when the file content was last modified.
116+
struct timespec ctime; // Time when the file node was last modified.
114117

115118
// Reference to parent of current file node. This can be used to
116119
// traverse up the directory tree. A weak_ptr ensures that the ref
@@ -314,12 +317,42 @@ class File::Handle {
314317
// directory, for example).
315318
file->mode = (file->mode & S_IFMT) | (mode & ~S_IFMT);
316319
}
317-
time_t getCTime() { return file->ctime; }
318-
void setCTime(time_t time) { file->ctime = time; }
319-
time_t getMTime() { return file->mtime; }
320-
void setMTime(time_t time) { file->mtime = time; }
321-
time_t getATime() { return file->atime; }
322-
void setATime(time_t time) { file->atime = time; }
320+
struct timespec getCTime() {
321+
return file->ctime;
322+
}
323+
void setCTime(struct timespec time) {
324+
file->ctime = time;
325+
}
326+
// updateCTime() updates the ctime to the current time.
327+
void updateCTime() {
328+
struct timespec ts;
329+
clock_gettime(CLOCK_REALTIME, &ts);
330+
file->ctime = ts;
331+
}
332+
struct timespec getMTime() {
333+
return file->mtime;
334+
}
335+
void setMTime(struct timespec time) {
336+
file->mtime = time;
337+
}
338+
// updateMTime() updates the mtime to the current time.
339+
void updateMTime() {
340+
struct timespec ts;
341+
clock_gettime(CLOCK_REALTIME, &ts);
342+
file->mtime = ts;
343+
}
344+
struct timespec getATime() {
345+
return file->atime;
346+
}
347+
void setATime(struct timespec time) {
348+
file->atime = time;
349+
}
350+
// updateATime() updates the atime to the current time.
351+
void updateATime() {
352+
struct timespec ts;
353+
clock_gettime(CLOCK_REALTIME, &ts);
354+
file->atime = ts;
355+
}
323356

324357
// Note: parent.lock() creates a new shared_ptr to the same Directory
325358
// specified by the parent weak_ptr.

system/lib/wasmfs/syscalls.cpp

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <utility>
2525
#include <vector>
2626
#include <wasi/api.h>
27+
#include <time.h>
2728

2829
#include "backend.h"
2930
#include "file.h"
@@ -167,7 +168,7 @@ static __wasi_errno_t writeAtOffset(OffsetHandling setOffset,
167168
lockedOpenFile.setPosition(offset + bytesWritten);
168169
}
169170
if (bytesWritten) {
170-
lockedFile.setMTime(time(NULL));
171+
lockedFile.updateMTime();
171172
}
172173
return __WASI_ERRNO_SUCCESS;
173174
}
@@ -383,9 +384,9 @@ int __syscall_newfstatat(int dirfd, intptr_t path, intptr_t buf, int flags) {
383384
buffer->st_blocks = (buffer->st_size + 511) / 512;
384385
// Specifies the preferred blocksize for efficient disk I/O.
385386
buffer->st_blksize = 4096;
386-
buffer->st_atim.tv_sec = lockedFile.getATime();
387-
buffer->st_mtim.tv_sec = lockedFile.getMTime();
388-
buffer->st_ctim.tv_sec = lockedFile.getCTime();
387+
buffer->st_atim = lockedFile.getATime();
388+
buffer->st_mtim = lockedFile.getMTime();
389+
buffer->st_ctim = lockedFile.getCTime();
389390
return __WASI_ERRNO_SUCCESS;
390391
}
391392

@@ -1093,21 +1094,23 @@ int __syscall_utimensat(int dirFD, intptr_t path_, intptr_t times_, int flags) {
10931094
return err;
10941095
}
10951096

1096-
// TODO: Set tv_nsec (nanoseconds) as well.
10971097
// TODO: Handle tv_nsec being UTIME_NOW or UTIME_OMIT.
10981098
// TODO: Check for write access to the file (see man page for specifics).
1099-
time_t aSeconds, mSeconds;
1099+
struct timespec aTime, mTime;
1100+
11001101
if (times == NULL) {
1101-
aSeconds = time(NULL);
1102-
mSeconds = aSeconds;
1102+
struct timespec ts;
1103+
clock_gettime(CLOCK_REALTIME, &ts);
1104+
aTime = ts;
1105+
mTime = ts;
11031106
} else {
1104-
aSeconds = times[0].tv_sec;
1105-
mSeconds = times[1].tv_sec;
1107+
aTime = times[0];
1108+
mTime = times[1];
11061109
}
11071110

11081111
auto locked = parsed.getFile()->locked();
1109-
locked.setATime(aSeconds);
1110-
locked.setMTime(mSeconds);
1112+
locked.setATime(aTime);
1113+
locked.setMTime(mTime);
11111114

11121115
return 0;
11131116
}
@@ -1131,7 +1134,7 @@ int __syscall_fchmodat(int dirfd, intptr_t path, int mode, ...) {
11311134
auto lockedFile = parsed.getFile()->locked();
11321135
lockedFile.setMode(mode);
11331136
// On POSIX, ctime is updated on metadata changes, like chmod.
1134-
lockedFile.setCTime(time(NULL));
1137+
lockedFile.updateCTime();
11351138
return 0;
11361139
}
11371140

@@ -1146,7 +1149,7 @@ int __syscall_fchmod(int fd, int mode) {
11461149
}
11471150
auto lockedFile = openFile->locked().getFile()->locked();
11481151
lockedFile.setMode(mode);
1149-
lockedFile.setCTime(time(NULL));
1152+
lockedFile.updateCTime();
11501153
return 0;
11511154
}
11521155

test/fs/test_fs_js_api.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,11 @@ void test_fs_utime() {
374374
assert(utimeStats.st_atime == 10);
375375
assert(utimeStats.st_atim.tv_sec == 10);
376376

377-
// WasmFS correctly sets both times, but the legacy API sets both times to the max of atime and mtime.
377+
// WasmFS correctly sets both times, but the legacy API sets both times to the max of atime and mtime
378+
// and does not correctly handle nanseconds.
378379
#if WASMFS
380+
assert(utimeStats.st_atim.tv_nsec == 500000000);
381+
379382
assert(utimeStats.st_mtime == 8);
380383
assert(utimeStats.st_mtim.tv_sec == 8);
381384
#else

test/other/metadce/test_metadce_cxx_wasmfs.imports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
env.__cxa_throw
2+
env._emscripten_get_now_is_monotonic
23
env._wasmfs_copy_preloaded_file_data
34
env._wasmfs_get_num_preloaded_dirs
45
env._wasmfs_get_num_preloaded_files
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
12363
1+
12507

test/other/metadce/test_metadce_cxx_wasmfs.sent

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
__cxa_throw
2+
_emscripten_get_now_is_monotonic
23
_wasmfs_copy_preloaded_file_data
34
_wasmfs_get_num_preloaded_dirs
45
_wasmfs_get_num_preloaded_files
@@ -11,6 +12,7 @@ abort
1112
emscripten_console_error
1213
emscripten_date_now
1314
emscripten_err
15+
emscripten_get_now
1416
emscripten_memcpy_big
1517
emscripten_out
1618
emscripten_resize_heap
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
164024
1+
164449
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
q
21
r
32
s
43
t
4+
u

test/other/metadce/test_metadce_files_wasmfs.funcs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
$__clock_gettime
12
$__cxx_global_array_dtor
23
$__cxx_global_array_dtor.1
34
$__cxx_global_array_dtor.2
@@ -27,7 +28,6 @@ $__pthread_mutex_lock
2728
$__stdio_close
2829
$__stdio_seek
2930
$__stdio_write
30-
$__time
3131
$__unlockfile
3232
$__wasi_fd_close
3333
$__wasi_fd_write

test/other/metadce/test_metadce_files_wasmfs.imports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ a.m
1414
a.n
1515
a.o
1616
a.p
17+
a.q
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6830
1+
6902

test/other/metadce/test_metadce_files_wasmfs.sent

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ m
1414
n
1515
o
1616
p
17+
q
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
51954
1+
52403

0 commit comments

Comments
 (0)