mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
fs: implement lutimes
PR-URL: https://github.com/nodejs/node/pull/33399 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>
This commit is contained in:
1 parent
86cbad837b
commit
e202df8e4b
5 files changed
+159
-28
No files matched your search
@@ -2396,6 +2396,38 @@ changes:
|
||||
|
||||
Synchronous lchown(2). Returns `undefined`.
|
||||
|
||||
## `fs.lutimes(path, atime, mtime, callback)`
|
||||
<!-- YAML
|
||||
addded: REPLACEME
|
||||
-->
|
||||
|
||||
* `path` {string|Buffer|URL}
|
||||
* `atime` {number|string|Date}
|
||||
* `mtime` {number|string|Date}
|
||||
* `callback` {Function}
|
||||
* `err` {Error}
|
||||
|
||||
Changes the access and modification times of a file in the same way as
|
||||
[`fs.utimes()`][], with the difference that if the path refers to a symbolic
|
||||
link, then the link is not dereferenced: instead, the timestamps of the
|
||||
symbolic link itself are changed.
|
||||
|
||||
No arguments other than a possible exception are given to the completion
|
||||
callback.
|
||||
|
||||
## `fs.lutimesSync(path, atime, mtime)`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* `path` {string|Buffer|URL}
|
||||
* `atime` {number|string|Date}
|
||||
* `mtime` {number|string|Date}
|
||||
|
||||
Change the file system timestamps of the symbolic link referenced by `path`.
|
||||
Returns `undefined`, or throws an exception when parameters are incorrect or
|
||||
the operation fails. This is the synchronous version of [`fs.lutimes()`][].
|
||||
|
||||
## `fs.link(existingPath, newPath, callback)`
|
||||
<!-- YAML
|
||||
added: v0.1.31
|
||||
@@ -5035,6 +5067,23 @@ changes:
|
||||
Changes the ownership on a symbolic link then resolves the `Promise` with
|
||||
no arguments upon success.
|
||||
|
||||
### `fsPromises.lutimes(path, atime, mtime)`
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
* `path` {string|Buffer|URL}
|
||||
* `atime` {number|string|Date}
|
||||
* `mtime` {number|string|Date}
|
||||
* Returns: {Promise}
|
||||
|
||||
Changes the access and modification times of a file in the same way as
|
||||
[`fsPromises.utimes()`][], with the difference that if the path refers to a
|
||||
symbolic link, then the link is not dereferenced: instead, the timestamps of
|
||||
the symbolic link itself are changed.
|
||||
|
||||
Upon success, the `Promise` is resolved without arguments.
|
||||
|
||||
### `fsPromises.link(existingPath, newPath)`
|
||||
<!-- YAML
|
||||
added: v10.0.0
|
||||
@@ -5853,6 +5902,7 @@ the file contents.
|
||||
[`fs.ftruncate()`]: #fs_fs_ftruncate_fd_len_callback
|
||||
[`fs.futimes()`]: #fs_fs_futimes_fd_atime_mtime_callback
|
||||
[`fs.lstat()`]: #fs_fs_lstat_path_options_callback
|
||||
[`fs.lutimes()`]: #fs_fs_lutimes_path_atime_mtime_callback
|
||||
[`fs.mkdir()`]: #fs_fs_mkdir_path_options_callback
|
||||
[`fs.mkdtemp()`]: #fs_fs_mkdtemp_prefix_options_callback
|
||||
[`fs.open()`]: #fs_fs_open_path_flags_mode_callback
|
||||
@@ -5876,6 +5926,7 @@ the file contents.
|
||||
[`fs.writev()`]: #fs_fs_writev_fd_buffers_position_callback
|
||||
[`fsPromises.open()`]: #fs_fspromises_open_path_flags_mode
|
||||
[`fsPromises.opendir()`]: #fs_fspromises_opendir_path_options
|
||||
[`fsPromises.utimes()`]: #fs_fspromises_utimes_path_atime_mtime
|
||||
[`inotify(7)`]: http://man7.org/linux/man-pages/man7/inotify.7.html
|
||||
[`kqueue(2)`]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
|
||||
[`net.Socket`]: net.html#net_class_net_socket
|
||||
|
||||
@@ -1325,6 +1325,28 @@ function futimesSync(fd, atime, mtime) {
|
||||
handleErrorFromBinding(ctx);
|
||||
}
|
||||
|
||||
function lutimes(path, atime, mtime, callback) {
|
||||
callback = makeCallback(callback);
|
||||
path = getValidatedPath(path);
|
||||
|
||||
const req = new FSReqCallback();
|
||||
req.oncomplete = callback;
|
||||
binding.lutimes(pathModule.toNamespacedPath(path),
|
||||
toUnixTimestamp(atime),
|
||||
toUnixTimestamp(mtime),
|
||||
req);
|
||||
}
|
||||
|
||||
function lutimesSync(path, atime, mtime) {
|
||||
path = getValidatedPath(path);
|
||||
const ctx = { path };
|
||||
binding.lutimes(pathModule.toNamespacedPath(path),
|
||||
toUnixTimestamp(atime),
|
||||
toUnixTimestamp(mtime),
|
||||
undefined, ctx);
|
||||
handleErrorFromBinding(ctx);
|
||||
}
|
||||
|
||||
function writeAll(fd, isUserFd, buffer, offset, length, callback) {
|
||||
// write(fd, buffer, offset, length, position, callback)
|
||||
fs.write(fd, buffer, offset, length, null, (writeErr, written) => {
|
||||
@@ -1971,6 +1993,8 @@ module.exports = fs = {
|
||||
linkSync,
|
||||
lstat,
|
||||
lstatSync,
|
||||
lutimes,
|
||||
lutimesSync,
|
||||
mkdir,
|
||||
mkdirSync,
|
||||
mkdtemp,
|
||||
|
||||
@@ -510,6 +510,14 @@ async function futimes(handle, atime, mtime) {
|
||||
return binding.futimes(handle.fd, atime, mtime, kUsePromises);
|
||||
}
|
||||
|
||||
async function lutimes(path, atime, mtime) {
|
||||
path = getValidatedPath(path);
|
||||
return binding.lutimes(pathModule.toNamespacedPath(path),
|
||||
toUnixTimestamp(atime),
|
||||
toUnixTimestamp(mtime),
|
||||
kUsePromises);
|
||||
}
|
||||
|
||||
async function realpath(path, options) {
|
||||
options = getOptions(options, {});
|
||||
path = getValidatedPath(path);
|
||||
@@ -582,6 +590,7 @@ module.exports = {
|
||||
lchown,
|
||||
chown,
|
||||
utimes,
|
||||
lutimes,
|
||||
realpath,
|
||||
mkdtemp,
|
||||
writeFile,
|
||||
|
||||
@@ -2304,6 +2304,35 @@ static void FUTimes(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
}
|
||||
|
||||
static void LUTimes(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
const int argc = args.Length();
|
||||
CHECK_GE(argc, 3);
|
||||
|
||||
BufferValue path(env->isolate(), args[0]);
|
||||
CHECK_NOT_NULL(*path);
|
||||
|
||||
CHECK(args[1]->IsNumber());
|
||||
const double atime = args[1].As<Number>()->Value();
|
||||
|
||||
CHECK(args[2]->IsNumber());
|
||||
const double mtime = args[2].As<Number>()->Value();
|
||||
|
||||
FSReqBase* req_wrap_async = GetReqWrap(args, 3);
|
||||
if (req_wrap_async != nullptr) { // lutimes(path, atime, mtime, req)
|
||||
AsyncCall(env, req_wrap_async, args, "lutime", UTF8, AfterNoArgs,
|
||||
uv_fs_lutime, *path, atime, mtime);
|
||||
} else { // lutimes(path, atime, mtime, undefined, ctx)
|
||||
CHECK_EQ(argc, 5);
|
||||
FSReqWrapSync req_wrap_sync;
|
||||
FS_SYNC_TRACE_BEGIN(lutimes);
|
||||
SyncCall(env, args[4], &req_wrap_sync, "lutime",
|
||||
uv_fs_lutime, *path, atime, mtime);
|
||||
FS_SYNC_TRACE_END(lutimes);
|
||||
}
|
||||
}
|
||||
|
||||
static void Mkdtemp(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
Isolate* isolate = env->isolate();
|
||||
@@ -2399,6 +2428,7 @@ void Initialize(Local<Object> target,
|
||||
|
||||
env->SetMethod(target, "utimes", UTimes);
|
||||
env->SetMethod(target, "futimes", FUTimes);
|
||||
env->SetMethod(target, "lutimes", LUTimes);
|
||||
|
||||
env->SetMethod(target, "mkdtemp", Mkdtemp);
|
||||
|
||||
|
||||
@@ -24,13 +24,17 @@ const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const util = require('util');
|
||||
const fs = require('fs');
|
||||
const url = require('url');
|
||||
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
tmpdir.refresh();
|
||||
|
||||
function stat_resource(resource) {
|
||||
const lpath = `${tmpdir.path}/symlink`;
|
||||
fs.symlinkSync('unoent-entry', lpath);
|
||||
|
||||
function stat_resource(resource, statSync = fs.statSync) {
|
||||
if (typeof resource === 'string') {
|
||||
return fs.statSync(resource);
|
||||
return statSync(resource);
|
||||
}
|
||||
const stats = fs.fstatSync(resource);
|
||||
// Ensure mtime has been written to disk
|
||||
@@ -41,9 +45,9 @@ function stat_resource(resource) {
|
||||
return fs.fstatSync(resource);
|
||||
}
|
||||
|
||||
function check_mtime(resource, mtime) {
|
||||
function check_mtime(resource, mtime, statSync) {
|
||||
mtime = fs._toUnixTimestamp(mtime);
|
||||
const stats = stat_resource(resource);
|
||||
const stats = stat_resource(resource, statSync);
|
||||
const real_mtime = fs._toUnixTimestamp(stats.mtime);
|
||||
return mtime - real_mtime;
|
||||
}
|
||||
@@ -55,8 +59,8 @@ function expect_errno(syscall, resource, err, errno) {
|
||||
);
|
||||
}
|
||||
|
||||
function expect_ok(syscall, resource, err, atime, mtime) {
|
||||
const mtime_diff = check_mtime(resource, mtime);
|
||||
function expect_ok(syscall, resource, err, atime, mtime, statSync) {
|
||||
const mtime_diff = check_mtime(resource, mtime, statSync);
|
||||
assert(
|
||||
// Check up to single-second precision.
|
||||
// Sub-second precision is OS and fs dependant.
|
||||
@@ -68,45 +72,55 @@ function expect_ok(syscall, resource, err, atime, mtime) {
|
||||
|
||||
const stats = fs.statSync(tmpdir.path);
|
||||
|
||||
const asPath = (path) => path;
|
||||
const asUrl = (path) => url.pathToFileURL(path);
|
||||
|
||||
const cases = [
|
||||
new Date('1982-09-10 13:37'),
|
||||
new Date(),
|
||||
123456.789,
|
||||
stats.mtime,
|
||||
['123456', -1],
|
||||
new Date('2017-04-08T17:59:38.008Z')
|
||||
[asPath, new Date('1982-09-10 13:37')],
|
||||
[asPath, new Date()],
|
||||
[asPath, 123456.789],
|
||||
[asPath, stats.mtime],
|
||||
[asPath, '123456', -1],
|
||||
[asPath, new Date('2017-04-08T17:59:38.008Z')],
|
||||
[asUrl, new Date()],
|
||||
];
|
||||
|
||||
runTests(cases.values());
|
||||
|
||||
function runTests(iter) {
|
||||
const { value, done } = iter.next();
|
||||
if (done) return;
|
||||
|
||||
// Support easy setting same or different atime / mtime values.
|
||||
const [atime, mtime] = Array.isArray(value) ? value : [value, value];
|
||||
const [pathType, atime, mtime = atime] = value;
|
||||
|
||||
let fd;
|
||||
//
|
||||
// test async code paths
|
||||
//
|
||||
fs.utimes(tmpdir.path, atime, mtime, common.mustCall((err) => {
|
||||
fs.utimes(pathType(tmpdir.path), atime, mtime, common.mustCall((err) => {
|
||||
expect_ok('utimes', tmpdir.path, err, atime, mtime);
|
||||
|
||||
fs.utimes('foobarbaz', atime, mtime, common.mustCall((err) => {
|
||||
expect_errno('utimes', 'foobarbaz', err, 'ENOENT');
|
||||
fs.lutimes(pathType(lpath), atime, mtime, common.mustCall((err) => {
|
||||
expect_ok('lutimes', lpath, err, atime, mtime, fs.lstatSync);
|
||||
|
||||
// don't close this fd
|
||||
if (common.isWindows) {
|
||||
fd = fs.openSync(tmpdir.path, 'r+');
|
||||
} else {
|
||||
fd = fs.openSync(tmpdir.path, 'r');
|
||||
}
|
||||
fs.utimes(pathType('foobarbaz'), atime, mtime, common.mustCall((err) => {
|
||||
expect_errno('utimes', 'foobarbaz', err, 'ENOENT');
|
||||
|
||||
fs.futimes(fd, atime, mtime, common.mustCall((err) => {
|
||||
expect_ok('futimes', fd, err, atime, mtime);
|
||||
// don't close this fd
|
||||
if (common.isWindows) {
|
||||
fd = fs.openSync(tmpdir.path, 'r+');
|
||||
} else {
|
||||
fd = fs.openSync(tmpdir.path, 'r');
|
||||
}
|
||||
|
||||
syncTests();
|
||||
fs.futimes(fd, atime, mtime, common.mustCall((err) => {
|
||||
expect_ok('futimes', fd, err, atime, mtime);
|
||||
|
||||
setImmediate(common.mustCall(runTests), iter);
|
||||
syncTests();
|
||||
|
||||
setImmediate(common.mustCall(runTests), iter);
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
@@ -115,9 +129,12 @@ function runTests(iter) {
|
||||
// test synchronized code paths, these functions throw on failure
|
||||
//
|
||||
function syncTests() {
|
||||
fs.utimesSync(tmpdir.path, atime, mtime);
|
||||
fs.utimesSync(pathType(tmpdir.path), atime, mtime);
|
||||
expect_ok('utimesSync', tmpdir.path, undefined, atime, mtime);
|
||||
|
||||
fs.lutimesSync(pathType(lpath), atime, mtime);
|
||||
expect_ok('lutimesSync', lpath, undefined, atime, mtime, fs.lstatSync);
|
||||
|
||||
// Some systems don't have futimes
|
||||
// if there's an error, it should be ENOSYS
|
||||
try {
|
||||
@@ -129,7 +146,7 @@ function runTests(iter) {
|
||||
|
||||
let err;
|
||||
try {
|
||||
fs.utimesSync('foobarbaz', atime, mtime);
|
||||
fs.utimesSync(pathType('foobarbaz'), atime, mtime);
|
||||
} catch (ex) {
|
||||
err = ex;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user