aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSk Sajidul Kadir <sheikh.sajid522@gmail.com>2020-02-29 23:29:15 +1100
committerBen Noordhuis <info@bnoordhuis.nl>2020-04-14 10:06:33 +0200
commitbd4292385f5b0a1be85d6c7dd7b51d4b22a4289c (patch)
tree6be0fc63b5956f1a08d630cd836eafba2ac9226c
parentdc7c874660526e4ed70c7c7579b974283c9ad6e0 (diff)
downloadlibuv-bd4292385f5b0a1be85d6c7dd7b51d4b22a4289c.tar.gz
libuv-bd4292385f5b0a1be85d6c7dd7b51d4b22a4289c.zip
fs: add uv_fs_lutime()
PR-URL: https://github.com/libuv/libuv/pull/2723 Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
-rw-r--r--docs/src/fs.rst14
-rw-r--r--include/uv.h9
-rw-r--r--src/unix/fs.c77
-rw-r--r--src/win/fs.c76
-rw-r--r--test/test-fs.c112
-rw-r--r--test/test-list.h2
6 files changed, 252 insertions, 38 deletions
diff --git a/docs/src/fs.rst b/docs/src/fs.rst
index 2943ead3..a475a460 100644
--- a/docs/src/fs.rst
+++ b/docs/src/fs.rst
@@ -100,7 +100,8 @@ Data types
UV_FS_OPENDIR,
UV_FS_READDIR,
UV_FS_CLOSEDIR,
- UV_FS_MKSTEMP
+ UV_FS_MKSTEMP,
+ UV_FS_LUTIME
} uv_fs_type;
.. c:type:: uv_statfs_t
@@ -402,12 +403,17 @@ API
.. c:function:: int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb)
.. c:function:: int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb)
+.. c:function:: int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, double mtime, uv_fs_cb cb)
- Equivalent to :man:`utime(2)` and :man:`futimes(3)` respectively.
+ Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively.
.. note::
- AIX: This function only works for AIX 7.1 and newer. It can still be called on older
- versions but will return ``UV_ENOSYS``.
+ z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return
+ ``UV_ENOSYS``.
+
+ .. note::
+ AIX: `uv_fs_futime()` and `uv_fs_lutime()` functions only work for AIX 7.1 and newer.
+ They can still be called on older versions but will return ``UV_ENOSYS``.
.. versionchanged:: 1.10.0 sub-second precission is supported on Windows
diff --git a/include/uv.h b/include/uv.h
index 9fb52e47..2e8072fd 100644
--- a/include/uv.h
+++ b/include/uv.h
@@ -1274,7 +1274,8 @@ typedef enum {
UV_FS_READDIR,
UV_FS_CLOSEDIR,
UV_FS_STATFS,
- UV_FS_MKSTEMP
+ UV_FS_MKSTEMP,
+ UV_FS_LUTIME
} uv_fs_type;
struct uv_dir_s {
@@ -1447,6 +1448,12 @@ UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
double atime,
double mtime,
uv_fs_cb cb);
+UV_EXTERN int uv_fs_lutime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb);
UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
uv_fs_t* req,
const char* path,
diff --git a/src/unix/fs.c b/src/unix/fs.c
index 4a472375..1b8d2ad1 100644
--- a/src/unix/fs.c
+++ b/src/unix/fs.c
@@ -205,6 +205,20 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
}
+UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
+ struct timespec ts;
+ ts.tv_sec = time;
+ ts.tv_nsec = (uint64_t)(time * 1000000) % 1000000 * 1000;
+ return ts;
+}
+
+UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
+ struct timeval tv;
+ tv.tv_sec = time;
+ tv.tv_usec = (uint64_t)(time * 1000000) % 1000000;
+ return tv;
+}
+
static ssize_t uv__fs_futime(uv_fs_t* req) {
#if defined(__linux__) \
|| defined(_AIX71) \
@@ -213,10 +227,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
* for the sake of consistency with other platforms.
*/
struct timespec ts[2];
- ts[0].tv_sec = req->atime;
- ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
- ts[1].tv_sec = req->mtime;
- ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
+ ts[0] = uv__fs_to_timespec(req->atime);
+ ts[1] = uv__fs_to_timespec(req->mtime);
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
return utimensat(req->file, NULL, ts, 0);
#else
@@ -230,10 +242,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
|| defined(__OpenBSD__) \
|| defined(__sun)
struct timeval tv[2];
- tv[0].tv_sec = req->atime;
- tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
- tv[1].tv_sec = req->mtime;
- tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
+ tv[0] = uv__fs_to_timeval(req->atime);
+ tv[1] = uv__fs_to_timeval(req->mtime);
# if defined(__sun)
return futimesat(req->file, NULL, tv);
# else
@@ -972,10 +982,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
* for the sake of consistency with other platforms.
*/
struct timespec ts[2];
- ts[0].tv_sec = req->atime;
- ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
- ts[1].tv_sec = req->mtime;
- ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
+ ts[0] = uv__fs_to_timespec(req->atime);
+ ts[1] = uv__fs_to_timespec(req->mtime);
return utimensat(AT_FDCWD, req->path, ts, 0);
#elif defined(__APPLE__) \
|| defined(__DragonFly__) \
@@ -984,10 +992,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
|| defined(__NetBSD__) \
|| defined(__OpenBSD__)
struct timeval tv[2];
- tv[0].tv_sec = req->atime;
- tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
- tv[1].tv_sec = req->mtime;
- tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
+ tv[0] = uv__fs_to_timeval(req->atime);
+ tv[1] = uv__fs_to_timeval(req->mtime);
return utimes(req->path, tv);
#elif defined(_AIX) \
&& !defined(_AIX71)
@@ -1010,6 +1016,31 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
}
+static ssize_t uv__fs_lutime(uv_fs_t* req) {
+#if defined(__linux__) || \
+ defined(_AIX71) || \
+ defined(__sun) || \
+ defined(__HAIKU__)
+ struct timespec ts[2];
+ ts[0] = uv__fs_to_timespec(req->atime);
+ ts[1] = uv__fs_to_timespec(req->mtime);
+ return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
+#elif defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__) || \
+ defined(__NetBSD__)
+ struct timeval tv[2];
+ tv[0] = uv__fs_to_timeval(req->atime);
+ tv[1] = uv__fs_to_timeval(req->mtime);
+ return lutimes(req->path, tv);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+
static ssize_t uv__fs_write(uv_fs_t* req) {
#if defined(__linux__)
static int no_pwritev;
@@ -1523,6 +1554,7 @@ static void uv__fs_work(struct uv__work* w) {
X(FSYNC, uv__fs_fsync(req));
X(FTRUNCATE, ftruncate(req->file, req->off));
X(FUTIME, uv__fs_futime(req));
+ X(LUTIME, uv__fs_lutime(req));
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
X(LINK, link(req->path, req->new_path));
X(MKDIR, mkdir(req->path, req->mode));
@@ -1709,6 +1741,19 @@ int uv_fs_futime(uv_loop_t* loop,
POST;
}
+int uv_fs_lutime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb) {
+ INIT(LUTIME);
+ PATH;
+ req->atime = atime;
+ req->mtime = mtime;
+ POST;
+}
+
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
INIT(LSTAT);
diff --git a/src/win/fs.c b/src/win/fs.c
index 8502b072..209f3d57 100644
--- a/src/win/fs.c
+++ b/src/win/fs.c
@@ -2225,34 +2225,68 @@ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
return 0;
}
-
-static void fs__utime(uv_fs_t* req) {
+INLINE static DWORD fs__utime_impl_from_path(WCHAR* path,
+ double atime,
+ double mtime,
+ int do_lutime) {
HANDLE handle;
+ DWORD flags;
+ DWORD ret;
- handle = CreateFileW(req->file.pathw,
+ flags = FILE_FLAG_BACKUP_SEMANTICS;
+ if (do_lutime) {
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+ }
+
+ handle = CreateFileW(path,
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
+ flags,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
+ ret = GetLastError();
+ } else if (fs__utime_handle(handle, atime, mtime) != 0) {
+ ret = GetLastError();
+ } else {
+ ret = 0;
}
- if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- CloseHandle(handle);
+ CloseHandle(handle);
+ return ret;
+}
+
+INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) {
+ DWORD error;
+
+ error = fs__utime_impl_from_path(req->file.pathw,
+ req->fs.time.atime,
+ req->fs.time.mtime,
+ do_lutime);
+
+ if (error != 0) {
+ if (do_lutime &&
+ (error == ERROR_SYMLINK_NOT_SUPPORTED ||
+ error == ERROR_NOT_A_REPARSE_POINT)) {
+ /* Opened file is a reparse point but not a symlink. Try again. */
+ fs__utime_impl(req, 0);
+ } else {
+ /* utime failed. */
+ SET_REQ_WIN32_ERROR(req, error);
+ }
+
return;
}
- CloseHandle(handle);
-
req->result = 0;
}
+static void fs__utime(uv_fs_t* req) {
+ fs__utime_impl(req, /* do_lutime */ 0);
+}
+
static void fs__futime(uv_fs_t* req) {
int fd = req->file.fd;
@@ -2274,6 +2308,10 @@ static void fs__futime(uv_fs_t* req) {
req->result = 0;
}
+static void fs__lutime(uv_fs_t* req) {
+ fs__utime_impl(req, /* do_lutime */ 1);
+}
+
static void fs__link(uv_fs_t* req) {
DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
@@ -2670,6 +2708,7 @@ static void uv__fs_work(struct uv__work* w) {
XX(FTRUNCATE, ftruncate)
XX(UTIME, utime)
XX(FUTIME, futime)
+ XX(LUTIME, lutime)
XX(ACCESS, access)
XX(CHMOD, chmod)
XX(FCHMOD, fchmod)
@@ -3222,6 +3261,21 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
POST;
}
+int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
+ double mtime, uv_fs_cb cb) {
+ int err;
+
+ INIT(UV_FS_LUTIME);
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+ POST;
+}
+
int uv_fs_statfs(uv_loop_t* loop,
uv_fs_t* req,
diff --git a/test/test-fs.c b/test/test-fs.c
index d491efb4..2966a53b 100644
--- a/test/test-fs.c
+++ b/test/test-fs.c
@@ -95,6 +95,7 @@ static int readlink_cb_count;
static int realpath_cb_count;
static int utime_cb_count;
static int futime_cb_count;
+static int lutime_cb_count;
static int statfs_cb_count;
static uv_loop_t* loop;
@@ -806,12 +807,19 @@ TEST_IMPL(fs_file_loop) {
return 0;
}
-static void check_utime(const char* path, double atime, double mtime) {
+static void check_utime(const char* path,
+ double atime,
+ double mtime,
+ int test_lutime) {
uv_stat_t* s;
uv_fs_t req;
int r;
- r = uv_fs_stat(loop, &req, path, NULL);
+ if (test_lutime)
+ r = uv_fs_lstat(loop, &req, path, NULL);
+ else
+ r = uv_fs_stat(loop, &req, path, NULL);
+
ASSERT(r == 0);
ASSERT(req.result == 0);
@@ -832,7 +840,7 @@ static void utime_cb(uv_fs_t* req) {
ASSERT(req->fs_type == UV_FS_UTIME);
c = req->data;
- check_utime(c->path, c->atime, c->mtime);
+ check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0);
uv_fs_req_cleanup(req);
utime_cb_count++;
@@ -847,13 +855,27 @@ static void futime_cb(uv_fs_t* req) {
ASSERT(req->fs_type == UV_FS_FUTIME);
c = req->data;
- check_utime(c->path, c->atime, c->mtime);
+ check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0);
uv_fs_req_cleanup(req);
futime_cb_count++;
}
+static void lutime_cb(uv_fs_t* req) {
+ utime_check_t* c;
+
+ ASSERT(req->result == 0);
+ ASSERT(req->fs_type == UV_FS_LUTIME);
+
+ c = req->data;
+ check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 1);
+
+ uv_fs_req_cleanup(req);
+ lutime_cb_count++;
+}
+
+
TEST_IMPL(fs_file_async) {
int r;
@@ -2470,7 +2492,7 @@ TEST_IMPL(fs_utime) {
r = uv_fs_stat(NULL, &req, path, NULL);
ASSERT(r == 0);
ASSERT(req.result == 0);
- check_utime(path, atime, mtime);
+ check_utime(path, atime, mtime, /* test_lutime */ 0);
uv_fs_req_cleanup(&req);
atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
@@ -2576,7 +2598,7 @@ TEST_IMPL(fs_futime) {
r = uv_fs_stat(NULL, &req, path, NULL);
ASSERT(r == 0);
ASSERT(req.result == 0);
- check_utime(path, atime, mtime);
+ check_utime(path, atime, mtime, /* test_lutime */ 0);
uv_fs_req_cleanup(&req);
atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
@@ -2600,6 +2622,84 @@ TEST_IMPL(fs_futime) {
}
+TEST_IMPL(fs_lutime) {
+ utime_check_t checkme;
+ const char* path = "test_file";
+ const char* symlink_path = "test_file_symlink";
+ double atime;
+ double mtime;
+ uv_fs_t req;
+ int r, s;
+
+
+ /* Setup */
+ loop = uv_default_loop();
+ unlink(path);
+ r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
+ ASSERT(r >= 0);
+ ASSERT(req.result >= 0);
+ uv_fs_req_cleanup(&req);
+ uv_fs_close(loop, &req, r, NULL);
+
+ unlink(symlink_path);
+ s = uv_fs_symlink(NULL, &req, path, symlink_path, 0, NULL);
+#ifdef _WIN32
+ if (s == UV_EPERM) {
+ /*
+ * Creating a symlink before Windows 10 Creators Update was only allowed
+ * when running elevated console (with admin rights)
+ */
+ RETURN_SKIP(
+ "Symlink creation requires elevated console (with admin rights)");
+ }
+#endif
+ ASSERT(s == 0);
+ ASSERT(req.result == 0);
+ uv_fs_req_cleanup(&req);
+
+ /* Test the synchronous version. */
+ atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
+
+#ifdef _WIN32
+ mtime += 0.444; /* 1982-09-10 11:22:33.444 */
+#endif
+
+ checkme.atime = atime;
+ checkme.mtime = mtime;
+ checkme.path = symlink_path;
+ req.data = &checkme;
+
+ r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL);
+#if (defined(_AIX) && !defined(_AIX71)) || \
+ defined(__MVS__)
+ ASSERT(r == UV_ENOSYS);
+ RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1");
+#endif
+ ASSERT(r == 0);
+ lutime_cb(&req);
+ ASSERT(lutime_cb_count == 1);
+
+ /* Test the asynchronous version. */
+ atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */
+
+ checkme.atime = atime;
+ checkme.mtime = mtime;
+ checkme.path = symlink_path;
+
+ r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb);
+ ASSERT(r == 0);
+ uv_run(loop, UV_RUN_DEFAULT);
+ ASSERT(lutime_cb_count == 2);
+
+ /* Cleanup. */
+ unlink(path);
+ unlink(symlink_path);
+
+ MAKE_VALGRIND_HAPPY();
+ return 0;
+}
+
+
TEST_IMPL(fs_stat_missing_path) {
uv_fs_t req;
int r;
diff --git a/test/test-list.h b/test/test-list.h
index 003b8d26..eb666571 100644
--- a/test/test-list.h
+++ b/test/test-list.h
@@ -353,6 +353,7 @@ TEST_DECLARE (fs_fd_hash)
#endif
TEST_DECLARE (fs_utime)
TEST_DECLARE (fs_futime)
+TEST_DECLARE (fs_lutime)
TEST_DECLARE (fs_file_open_append)
TEST_DECLARE (fs_statfs)
TEST_DECLARE (fs_stat_missing_path)
@@ -969,6 +970,7 @@ TASK_LIST_START
TEST_ENTRY (fs_chown)
TEST_ENTRY (fs_utime)
TEST_ENTRY (fs_futime)
+ TEST_ENTRY (fs_lutime)
TEST_ENTRY (fs_readlink)
TEST_ENTRY (fs_realpath)
TEST_ENTRY (fs_symlink)