Skip to content

Commit 8803db6

Browse files
committed
Make JS FS support atime, mtime, and ctime as distinct values
1 parent 3f3f385 commit 8803db6

13 files changed

+76
-73
lines changed

src/library_fs.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ FS.staticInit();
146146
this.name = name;
147147
this.mode = mode;
148148
this.rdev = rdev;
149+
this.atime = this.mtime = this.ctime = Date.now();
149150
}
150151
get read() {
151152
return (this.mode & this.readMode) === this.readMode;
@@ -165,6 +166,12 @@ FS.staticInit();
165166
get isDevice() {
166167
return FS.isChrdev(this.mode);
167168
}
169+
get timestamp() {
170+
return this.atime;
171+
}
172+
set timestamp(val) {
173+
this.atime = this.mtime = this.ctime = val;
174+
}
168175
},
169176

170177
//
@@ -933,6 +940,7 @@ FS.staticInit();
933940
}
934941
node.node_ops.setattr(node, {
935942
mode: (mode & {{{ cDefs.S_IALLUGO }}}) | (node.mode & ~{{{ cDefs.S_IALLUGO }}}),
943+
ctime: Date.now()
936944
});
937945
},
938946
lchmod(path, mode) {
@@ -1005,7 +1013,8 @@ FS.staticInit();
10051013
var lookup = FS.lookupPath(path, { follow: true });
10061014
var node = lookup.node;
10071015
node.node_ops.setattr(node, {
1008-
timestamp: Math.max(atime, mtime)
1016+
atime: atime,
1017+
mtime: mtime
10091018
});
10101019
},
10111020
open(path, flags, mode) {
@@ -1608,7 +1617,7 @@ FS.staticInit();
16081617
buffer[offset+i] = result;
16091618
}
16101619
if (bytesRead) {
1611-
stream.node.timestamp = Date.now();
1620+
stream.node.atime = Date.now();
16121621
}
16131622
return bytesRead;
16141623
},
@@ -1621,7 +1630,7 @@ FS.staticInit();
16211630
}
16221631
}
16231632
if (length) {
1624-
stream.node.timestamp = Date.now();
1633+
stream.node.mtime = stream.node.ctime = Date.now();
16251634
}
16261635
return i;
16271636
}

src/library_lz4.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ addToLibrary({
7070
node.mode = mode;
7171
node.node_ops = LZ4.node_ops;
7272
node.stream_ops = LZ4.stream_ops;
73-
node.timestamp = (mtime || new Date).getTime();
73+
node.atime = node.mtime = node.ctime = (mtime || new Date).getTime();
7474
assert(LZ4.FILE_MODE !== LZ4.DIR_MODE);
7575
if (mode === LZ4.FILE_MODE) {
7676
node.size = contents.end - contents.start;
@@ -95,19 +95,18 @@ addToLibrary({
9595
gid: 0,
9696
rdev: 0,
9797
size: node.size,
98-
atime: new Date(node.timestamp),
99-
mtime: new Date(node.timestamp),
100-
ctime: new Date(node.timestamp),
98+
atime: new Date(node.atime),
99+
mtime: new Date(node.mtime),
100+
ctime: new Date(node.ctime),
101101
blksize: 4096,
102102
blocks: Math.ceil(node.size / 4096),
103103
};
104104
},
105105
setattr(node, attr) {
106-
if (attr.mode !== undefined) {
107-
node.mode = attr.mode;
108-
}
109-
if (attr.timestamp !== undefined) {
110-
node.timestamp = attr.timestamp;
106+
for (const key of ["mode", "atime", "mtime", "ctime"]) {
107+
if (attr[key]) {
108+
node[key] = attr[key];
109+
}
111110
}
112111
},
113112
lookup(parent, name) {

src/library_memfs.js

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ addToLibrary({
9292
node.node_ops = MEMFS.ops_table.chrdev.node;
9393
node.stream_ops = MEMFS.ops_table.chrdev.stream;
9494
}
95-
node.timestamp = Date.now();
95+
node.atime = node.mtime = node.ctime = Date.now();
9696
// add the new node to the parent
9797
if (parent) {
9898
parent.contents[name] = node;
99-
parent.timestamp = node.timestamp;
99+
parent.atime = parent.mtime = parent.ctime = node.atime;
100100
}
101101
return node;
102102
},
@@ -161,21 +161,20 @@ addToLibrary({
161161
} else {
162162
attr.size = 0;
163163
}
164-
attr.atime = new Date(node.timestamp);
165-
attr.mtime = new Date(node.timestamp);
166-
attr.ctime = new Date(node.timestamp);
164+
attr.atime = new Date(node.atime);
165+
attr.mtime = new Date(node.mtime);
166+
attr.ctime = new Date(node.ctime);
167167
// NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
168168
// but this is not required by the standard.
169169
attr.blksize = 4096;
170170
attr.blocks = Math.ceil(attr.size / attr.blksize);
171171
return attr;
172172
},
173173
setattr(node, attr) {
174-
if (attr.mode !== undefined) {
175-
node.mode = attr.mode;
176-
}
177-
if (attr.timestamp !== undefined) {
178-
node.timestamp = attr.timestamp;
174+
for (const key of ["mode", "atime", "mtime", "ctime"]) {
175+
if (attr[key]) {
176+
node[key] = attr[key];
177+
}
179178
}
180179
if (attr.size !== undefined) {
181180
MEMFS.resizeFileStorage(node, attr.size);
@@ -207,22 +206,21 @@ addToLibrary({
207206
}
208207
// do the internal rewiring
209208
delete old_node.parent.contents[old_node.name];
210-
old_node.parent.timestamp = Date.now()
211-
old_node.name = new_name;
212209
new_dir.contents[new_name] = old_node;
213-
new_dir.timestamp = old_node.parent.timestamp;
210+
old_node.name = new_name;
211+
new_dir.ctime = new_dir.mtime = old_node.parent.ctime = old_node.parent.mtime = Date.now();
214212
},
215213
unlink(parent, name) {
216214
delete parent.contents[name];
217-
parent.timestamp = Date.now();
215+
parent.ctime = parent.mtime = Date.now();
218216
},
219217
rmdir(parent, name) {
220218
var node = FS.lookupNode(parent, name);
221219
for (var i in node.contents) {
222220
throw new FS.ErrnoError({{{ cDefs.ENOTEMPTY }}});
223221
}
224222
delete parent.contents[name];
225-
parent.timestamp = Date.now();
223+
parent.ctime = parent.mtime = Date.now();
226224
},
227225
readdir(node) {
228226
var entries = ['.', '..'];
@@ -282,7 +280,7 @@ addToLibrary({
282280

283281
if (!length) return 0;
284282
var node = stream.node;
285-
node.timestamp = Date.now();
283+
node.mtime = node.ctime = Date.now();
286284

287285
if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array?
288286
if (canOwn) {

src/library_nodefs.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,11 @@ addToLibrary({
161161
// update the common node structure mode as well
162162
node.mode = attr.mode;
163163
}
164-
if (attr.timestamp !== undefined) {
165-
var date = new Date(attr.timestamp);
166-
fs.utimesSync(path, date, date);
164+
if (attr.atime || attr.mtime) {
165+
var atime = attr.atime && new Date(attr.atime);
166+
var mtime = attr.mtime && new Date(attr.mtime);
167+
console.log("atime", atime, "mtime", mtime);
168+
fs.utimesSync(path, atime, mtime);
167169
}
168170
if (attr.size !== undefined) {
169171
fs.truncateSync(path, attr.size);

src/library_noderawfs.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ addToLibrary({
9595
// -1 here for atime or mtime means UTIME_OMIT was passed. Since node
9696
// doesn't support this concept we need to first find the existing
9797
// timestamps in order to preserve them.
98-
if (atime == -1 || mtime == -1) {
98+
if (atime === undefined || mtime === undefined) {
9999
var st = fs.statSync(path);
100-
if (atime == -1) atime = st.atimeMs;
101-
if (mtime == -1) mtime = st.mtimeMs;
100+
atime ||= st.atimeMs;
101+
mtime ||= st.mtimeMs;
102102
}
103103
fs.utimesSync(path, atime/1000, mtime/1000);
104104
},

src/library_proxyfs.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ addToLibrary({
6363
// update the common node structure mode as well
6464
node.mode = attr.mode;
6565
}
66-
if (attr.timestamp !== undefined) {
67-
var date = new Date(attr.timestamp);
68-
node.mount.opts.fs.utime(path, date, date);
66+
if (attr.atime || attr.mtime) {
67+
var atime = new Date(attr.atime || attr.mtime);
68+
var mtime = new Date(attr.mtime || attr.atime);
69+
node.mount.opts.fs.utime(path, atime, mtime);
6970
}
7071
if (attr.size !== undefined) {
7172
node.mount.opts.fs.truncate(path, attr.size);

src/library_syscall.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -980,7 +980,7 @@ var SyscallsLibrary = {
980980
if (nanoseconds == {{{ cDefs.UTIME_NOW }}}) {
981981
atime = now;
982982
} else if (nanoseconds == {{{ cDefs.UTIME_OMIT }}}) {
983-
atime = -1;
983+
atime = undefined;
984984
} else {
985985
atime = (seconds*1000) + (nanoseconds/(1000*1000));
986986
}
@@ -990,15 +990,14 @@ var SyscallsLibrary = {
990990
if (nanoseconds == {{{ cDefs.UTIME_NOW }}}) {
991991
mtime = now;
992992
} else if (nanoseconds == {{{ cDefs.UTIME_OMIT }}}) {
993-
mtime = -1;
993+
mtime = undefined;
994994
} else {
995995
mtime = (seconds*1000) + (nanoseconds/(1000*1000));
996996
}
997997
}
998-
// -1 here means UTIME_OMIT was passed. FS.utime tables the max of these
999-
// two values and sets the timestamp to that single value. If both were
1000-
// set to UTIME_OMIT then we can skip the call completely.
1001-
if (mtime != -1 || atime != -1) {
998+
// undefined here means UTIME_OMIT was passed. If both were set to UTIME_OMIT then
999+
// we can skip the call completely.
1000+
if (mtime !== undefined || atime !== undefined) {
10021001
FS.utime(path, atime, mtime);
10031002
}
10041003
return 0;

src/library_tty.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ addToLibrary({
7979
buffer[offset+i] = result;
8080
}
8181
if (bytesRead) {
82-
stream.node.timestamp = Date.now();
82+
stream.node.atime = Date.now();
8383
}
8484
return bytesRead;
8585
},
@@ -95,7 +95,7 @@ addToLibrary({
9595
throw new FS.ErrnoError({{{ cDefs.EIO }}});
9696
}
9797
if (length) {
98-
stream.node.timestamp = Date.now();
98+
stream.node.mtime = stream.node.ctime = Date.now();
9999
}
100100
return i;
101101
}

src/library_workerfs.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ addToLibrary({
5757
node.mode = mode;
5858
node.node_ops = WORKERFS.node_ops;
5959
node.stream_ops = WORKERFS.stream_ops;
60-
node.timestamp = (mtime || new Date).getTime();
60+
node.atime = node.mtime = node.ctime = (mtime || new Date).getTime();
6161
assert(WORKERFS.FILE_MODE !== WORKERFS.DIR_MODE);
6262
if (mode === WORKERFS.FILE_MODE) {
6363
node.size = contents.size;
@@ -82,19 +82,18 @@ addToLibrary({
8282
gid: 0,
8383
rdev: 0,
8484
size: node.size,
85-
atime: new Date(node.timestamp),
86-
mtime: new Date(node.timestamp),
87-
ctime: new Date(node.timestamp),
85+
atime: new Date(node.atime),
86+
mtime: new Date(node.mtime),
87+
ctime: new Date(node.ctime),
8888
blksize: 4096,
8989
blocks: Math.ceil(node.size / 4096),
9090
};
9191
},
9292
setattr(node, attr) {
93-
if (attr.mode !== undefined) {
94-
node.mode = attr.mode;
95-
}
96-
if (attr.timestamp !== undefined) {
97-
node.timestamp = attr.timestamp;
93+
for (const key of ["mode", "atime", "mtime", "ctime"]) {
94+
if (attr[key]) {
95+
node[key] = attr[key];
96+
}
9897
}
9998
},
10099
lookup(parent, name) {

test/fs/test_fs_js_api.c

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -439,17 +439,10 @@ void test_fs_utime() {
439439
assert(utimeStats.st_atime == 10);
440440
assert(utimeStats.st_atim.tv_sec == 10);
441441

442-
// WasmFS correctly sets both times, but the legacy API sets both times to the max of atime and mtime
443-
// and does not correctly handle nanseconds.
444-
#if WASMFS
445442
assert(utimeStats.st_atim.tv_nsec == 500000000);
446443

447444
assert(utimeStats.st_mtime == 8);
448445
assert(utimeStats.st_mtim.tv_sec == 8);
449-
#else
450-
assert(utimeStats.st_mtime == 10);
451-
assert(utimeStats.st_mtim.tv_sec == 10);
452-
#endif
453446

454447
remove("utimetest");
455448
}

0 commit comments

Comments
 (0)