Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a19933f

Browse filesBrowse files
arcanisaddaleax
authored andcommitted
fs: implement lutimes
PR-URL: #33399 Backport-PR-URL: #35320 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Jiawen Geng <technicalcute@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
1 parent 232f6e1 commit a19933f
Copy full SHA for a19933f

File tree

Expand file treeCollapse file tree

5 files changed

+159
-28
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+159
-28
lines changed
Open diff view settings
Collapse file

‎doc/api/fs.md‎

Copy file name to clipboardExpand all lines: doc/api/fs.md
+51Lines changed: 51 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2368,6 +2368,38 @@ changes:
23682368

23692369
Synchronous lchown(2). Returns `undefined`.
23702370

2371+
## `fs.lutimes(path, atime, mtime, callback)`
2372+
<!-- YAML
2373+
added: REPLACEME
2374+
-->
2375+
2376+
* `path` {string|Buffer|URL}
2377+
* `atime` {number|string|Date}
2378+
* `mtime` {number|string|Date}
2379+
* `callback` {Function}
2380+
* `err` {Error}
2381+
2382+
Changes the access and modification times of a file in the same way as
2383+
[`fs.utimes()`][], with the difference that if the path refers to a symbolic
2384+
link, then the link is not dereferenced: instead, the timestamps of the
2385+
symbolic link itself are changed.
2386+
2387+
No arguments other than a possible exception are given to the completion
2388+
callback.
2389+
2390+
## `fs.lutimesSync(path, atime, mtime)`
2391+
<!-- YAML
2392+
added: REPLACEME
2393+
-->
2394+
2395+
* `path` {string|Buffer|URL}
2396+
* `atime` {number|string|Date}
2397+
* `mtime` {number|string|Date}
2398+
2399+
Change the file system timestamps of the symbolic link referenced by `path`.
2400+
Returns `undefined`, or throws an exception when parameters are incorrect or
2401+
the operation fails. This is the synchronous version of [`fs.lutimes()`][].
2402+
23712403
## `fs.link(existingPath, newPath, callback)`
23722404
<!-- YAML
23732405
added: v0.1.31
@@ -4946,6 +4978,23 @@ changes:
49464978
Changes the ownership on a symbolic link then resolves the `Promise` with
49474979
no arguments upon success.
49484980

4981+
### `fsPromises.lutimes(path, atime, mtime)`
4982+
<!-- YAML
4983+
added: REPLACEME
4984+
-->
4985+
4986+
* `path` {string|Buffer|URL}
4987+
* `atime` {number|string|Date}
4988+
* `mtime` {number|string|Date}
4989+
* Returns: {Promise}
4990+
4991+
Changes the access and modification times of a file in the same way as
4992+
[`fsPromises.utimes()`][], with the difference that if the path refers to a
4993+
symbolic link, then the link is not dereferenced: instead, the timestamps of
4994+
the symbolic link itself are changed.
4995+
4996+
Upon success, the `Promise` is resolved without arguments.
4997+
49494998
### `fsPromises.link(existingPath, newPath)`
49504999
<!-- YAML
49515000
added: v10.0.0
@@ -5755,6 +5804,7 @@ the file contents.
57555804
[`fs.ftruncate()`]: #fs_fs_ftruncate_fd_len_callback
57565805
[`fs.futimes()`]: #fs_fs_futimes_fd_atime_mtime_callback
57575806
[`fs.lstat()`]: #fs_fs_lstat_path_options_callback
5807+
[`fs.lutimes()`]: #fs_fs_lutimes_path_atime_mtime_callback
57585808
[`fs.mkdir()`]: #fs_fs_mkdir_path_options_callback
57595809
[`fs.mkdtemp()`]: #fs_fs_mkdtemp_prefix_options_callback
57605810
[`fs.open()`]: #fs_fs_open_path_flags_mode_callback
@@ -5778,6 +5828,7 @@ the file contents.
57785828
[`fs.writev()`]: #fs_fs_writev_fd_buffers_position_callback
57795829
[`fsPromises.open()`]: #fs_fspromises_open_path_flags_mode
57805830
[`fsPromises.opendir()`]: #fs_fspromises_opendir_path_options
5831+
[`fsPromises.utimes()`]: #fs_fspromises_utimes_path_atime_mtime
57815832
[`inotify(7)`]: http://man7.org/linux/man-pages/man7/inotify.7.html
57825833
[`kqueue(2)`]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
57835834
[`net.Socket`]: net.html#net_class_net_socket
Collapse file

‎lib/fs.js‎

Copy file name to clipboardExpand all lines: lib/fs.js
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,28 @@ function futimesSync(fd, atime, mtime) {
13031303
handleErrorFromBinding(ctx);
13041304
}
13051305

1306+
function lutimes(path, atime, mtime, callback) {
1307+
callback = makeCallback(callback);
1308+
path = getValidatedPath(path);
1309+
1310+
const req = new FSReqCallback();
1311+
req.oncomplete = callback;
1312+
binding.lutimes(pathModule.toNamespacedPath(path),
1313+
toUnixTimestamp(atime),
1314+
toUnixTimestamp(mtime),
1315+
req);
1316+
}
1317+
1318+
function lutimesSync(path, atime, mtime) {
1319+
path = getValidatedPath(path);
1320+
const ctx = { path };
1321+
binding.lutimes(pathModule.toNamespacedPath(path),
1322+
toUnixTimestamp(atime),
1323+
toUnixTimestamp(mtime),
1324+
undefined, ctx);
1325+
handleErrorFromBinding(ctx);
1326+
}
1327+
13061328
function writeAll(fd, isUserFd, buffer, offset, length, callback) {
13071329
// write(fd, buffer, offset, length, position, callback)
13081330
fs.write(fd, buffer, offset, length, null, (writeErr, written) => {
@@ -1938,6 +1960,8 @@ module.exports = fs = {
19381960
linkSync,
19391961
lstat,
19401962
lstatSync,
1963+
lutimes,
1964+
lutimesSync,
19411965
mkdir,
19421966
mkdirSync,
19431967
mkdtemp,
Collapse file

‎lib/internal/fs/promises.js‎

Copy file name to clipboardExpand all lines: lib/internal/fs/promises.js
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,14 @@ async function futimes(handle, atime, mtime) {
474474
return binding.futimes(handle.fd, atime, mtime, kUsePromises);
475475
}
476476

477+
async function lutimes(path, atime, mtime) {
478+
path = getValidatedPath(path);
479+
return binding.lutimes(pathModule.toNamespacedPath(path),
480+
toUnixTimestamp(atime),
481+
toUnixTimestamp(mtime),
482+
kUsePromises);
483+
}
484+
477485
async function realpath(path, options) {
478486
options = getOptions(options, {});
479487
path = getValidatedPath(path);
@@ -541,6 +549,7 @@ module.exports = {
541549
lchown,
542550
chown,
543551
utimes,
552+
lutimes,
544553
realpath,
545554
mkdtemp,
546555
writeFile,
Collapse file

‎src/node_file.cc‎

Copy file name to clipboardExpand all lines: src/node_file.cc
+30Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,6 +2247,35 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
22472247
}
22482248
}
22492249

2250+
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
2251+
Environment* env = Environment::GetCurrent(args);
2252+
2253+
const int argc = args.Length();
2254+
CHECK_GE(argc, 3);
2255+
2256+
BufferValue path(env->isolate(), args[0]);
2257+
CHECK_NOT_NULL(*path);
2258+
2259+
CHECK(args[1]->IsNumber());
2260+
const double atime = args[1].As<Number>()->Value();
2261+
2262+
CHECK(args[2]->IsNumber());
2263+
const double mtime = args[2].As<Number>()->Value();
2264+
2265+
FSReqBase* req_wrap_async = GetReqWrap(env, args[3]);
2266+
if (req_wrap_async != nullptr) { // lutimes(path, atime, mtime, req)
2267+
AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
2268+
uv_fs_lutime, *path, atime, mtime);
2269+
} else { // lutimes(path, atime, mtime, undefined, ctx)
2270+
CHECK_EQ(argc, 5);
2271+
FSReqWrapSync req_wrap_sync;
2272+
FS_SYNC_TRACE_BEGIN(lutimes);
2273+
SyncCall(env, args[4], &req_wrap_sync, "lutime",
2274+
uv_fs_lutime, *path, atime, mtime);
2275+
FS_SYNC_TRACE_END(lutimes);
2276+
}
2277+
}
2278+
22502279
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
22512280
Environment* env = Environment::GetCurrent(args);
22522281
Isolate* isolate = env->isolate();
@@ -2329,6 +2358,7 @@ void Initialize(Local<Object> target,
23292358

23302359
env->SetMethod(target, "utimes", UTimes);
23312360
env->SetMethod(target, "futimes", FUTimes);
2361+
env->SetMethod(target, "lutimes", LUTimes);
23322362

23332363
env->SetMethod(target, "mkdtemp", Mkdtemp);
23342364

Collapse file

‎test/parallel/test-fs-utimes.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-fs-utimes.js
+45-28Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@ const common = require('../common');
2424
const assert = require('assert');
2525
const util = require('util');
2626
const fs = require('fs');
27+
const url = require('url');
2728

2829
const tmpdir = require('../common/tmpdir');
2930
tmpdir.refresh();
3031

31-
function stat_resource(resource) {
32+
const lpath = `${tmpdir.path}/symlink`;
33+
fs.symlinkSync('unoent-entry', lpath);
34+
35+
function stat_resource(resource, statSync = fs.statSync) {
3236
if (typeof resource === 'string') {
33-
return fs.statSync(resource);
37+
return statSync(resource);
3438
}
3539
const stats = fs.fstatSync(resource);
3640
// Ensure mtime has been written to disk
@@ -41,9 +45,9 @@ function stat_resource(resource) {
4145
return fs.fstatSync(resource);
4246
}
4347

44-
function check_mtime(resource, mtime) {
48+
function check_mtime(resource, mtime, statSync) {
4549
mtime = fs._toUnixTimestamp(mtime);
46-
const stats = stat_resource(resource);
50+
const stats = stat_resource(resource, statSync);
4751
const real_mtime = fs._toUnixTimestamp(stats.mtime);
4852
return mtime - real_mtime;
4953
}
@@ -55,8 +59,8 @@ function expect_errno(syscall, resource, err, errno) {
5559
);
5660
}
5761

58-
function expect_ok(syscall, resource, err, atime, mtime) {
59-
const mtime_diff = check_mtime(resource, mtime);
62+
function expect_ok(syscall, resource, err, atime, mtime, statSync) {
63+
const mtime_diff = check_mtime(resource, mtime, statSync);
6064
assert(
6165
// Check up to single-second precision.
6266
// Sub-second precision is OS and fs dependant.
@@ -68,45 +72,55 @@ function expect_ok(syscall, resource, err, atime, mtime) {
6872

6973
const stats = fs.statSync(tmpdir.path);
7074

75+
const asPath = (path) => path;
76+
const asUrl = (path) => url.pathToFileURL(path);
77+
7178
const cases = [
72-
new Date('1982-09-10 13:37'),
73-
new Date(),
74-
123456.789,
75-
stats.mtime,
76-
['123456', -1],
77-
new Date('2017-04-08T17:59:38.008Z')
79+
[asPath, new Date('1982-09-10 13:37')],
80+
[asPath, new Date()],
81+
[asPath, 123456.789],
82+
[asPath, stats.mtime],
83+
[asPath, '123456', -1],
84+
[asPath, new Date('2017-04-08T17:59:38.008Z')],
85+
[asUrl, new Date()],
7886
];
87+
7988
runTests(cases.values());
8089

8190
function runTests(iter) {
8291
const { value, done } = iter.next();
8392
if (done) return;
93+
8494
// Support easy setting same or different atime / mtime values.
85-
const [atime, mtime] = Array.isArray(value) ? value : [value, value];
95+
const [pathType, atime, mtime = atime] = value;
8696

8797
let fd;
8898
//
8999
// test async code paths
90100
//
91-
fs.utimes(tmpdir.path, atime, mtime, common.mustCall((err) => {
101+
fs.utimes(pathType(tmpdir.path), atime, mtime, common.mustCall((err) => {
92102
expect_ok('utimes', tmpdir.path, err, atime, mtime);
93103

94-
fs.utimes('foobarbaz', atime, mtime, common.mustCall((err) => {
95-
expect_errno('utimes', 'foobarbaz', err, 'ENOENT');
104+
fs.lutimes(pathType(lpath), atime, mtime, common.mustCall((err) => {
105+
expect_ok('lutimes', lpath, err, atime, mtime, fs.lstatSync);
106+
107+
fs.utimes(pathType('foobarbaz'), atime, mtime, common.mustCall((err) => {
108+
expect_errno('utimes', 'foobarbaz', err, 'ENOENT');
96109

97-
// don't close this fd
98-
if (common.isWindows) {
99-
fd = fs.openSync(tmpdir.path, 'r+');
100-
} else {
101-
fd = fs.openSync(tmpdir.path, 'r');
102-
}
110+
// don't close this fd
111+
if (common.isWindows) {
112+
fd = fs.openSync(tmpdir.path, 'r+');
113+
} else {
114+
fd = fs.openSync(tmpdir.path, 'r');
115+
}
103116

104-
fs.futimes(fd, atime, mtime, common.mustCall((err) => {
105-
expect_ok('futimes', fd, err, atime, mtime);
117+
fs.futimes(fd, atime, mtime, common.mustCall((err) => {
118+
expect_ok('futimes', fd, err, atime, mtime);
106119

107-
syncTests();
120+
syncTests();
108121

109-
setImmediate(common.mustCall(runTests), iter);
122+
setImmediate(common.mustCall(runTests), iter);
123+
}));
110124
}));
111125
}));
112126
}));
@@ -115,9 +129,12 @@ function runTests(iter) {
115129
// test synchronized code paths, these functions throw on failure
116130
//
117131
function syncTests() {
118-
fs.utimesSync(tmpdir.path, atime, mtime);
132+
fs.utimesSync(pathType(tmpdir.path), atime, mtime);
119133
expect_ok('utimesSync', tmpdir.path, undefined, atime, mtime);
120134

135+
fs.lutimesSync(pathType(lpath), atime, mtime);
136+
expect_ok('lutimesSync', lpath, undefined, atime, mtime, fs.lstatSync);
137+
121138
// Some systems don't have futimes
122139
// if there's an error, it should be ENOSYS
123140
try {
@@ -129,7 +146,7 @@ function runTests(iter) {
129146

130147
let err;
131148
try {
132-
fs.utimesSync('foobarbaz', atime, mtime);
149+
fs.utimesSync(pathType('foobarbaz'), atime, mtime);
133150
} catch (ex) {
134151
err = ex;
135152
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.