Skip to content

Commit bd42923

Browse files
SheikhSajidbnoordhuis
authored andcommitted
fs: add uv_fs_lutime()
PR-URL: #2723 Reviewed-By: Bartosz Sosnowski <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent dc7c874 commit bd42923

File tree

6 files changed

+252
-38
lines changed

6 files changed

+252
-38
lines changed

docs/src/fs.rst

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ Data types
100100
UV_FS_OPENDIR,
101101
UV_FS_READDIR,
102102
UV_FS_CLOSEDIR,
103-
UV_FS_MKSTEMP
103+
UV_FS_MKSTEMP,
104+
UV_FS_LUTIME
104105
} uv_fs_type;
105106

106107
.. c:type:: uv_statfs_t
@@ -402,12 +403,17 @@ API
402403
403404
.. 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)
404405
.. 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)
406+
.. 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)
405407
406-
Equivalent to :man:`utime(2)` and :man:`futimes(3)` respectively.
408+
Equivalent to :man:`utime(2)`, :man:`futimes(3)` and :man:`lutimes(3)` respectively.
407409
408410
.. note::
409-
AIX: This function only works for AIX 7.1 and newer. It can still be called on older
410-
versions but will return ``UV_ENOSYS``.
411+
z/OS: `uv_fs_lutime()` is not implemented for z/OS. It can still be called but will return
412+
``UV_ENOSYS``.
413+
414+
.. note::
415+
AIX: `uv_fs_futime()` and `uv_fs_lutime()` functions only work for AIX 7.1 and newer.
416+
They can still be called on older versions but will return ``UV_ENOSYS``.
411417
412418
.. versionchanged:: 1.10.0 sub-second precission is supported on Windows
413419

include/uv.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1274,7 +1274,8 @@ typedef enum {
12741274
UV_FS_READDIR,
12751275
UV_FS_CLOSEDIR,
12761276
UV_FS_STATFS,
1277-
UV_FS_MKSTEMP
1277+
UV_FS_MKSTEMP,
1278+
UV_FS_LUTIME
12781279
} uv_fs_type;
12791280

12801281
struct uv_dir_s {
@@ -1447,6 +1448,12 @@ UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
14471448
double atime,
14481449
double mtime,
14491450
uv_fs_cb cb);
1451+
UV_EXTERN int uv_fs_lutime(uv_loop_t* loop,
1452+
uv_fs_t* req,
1453+
const char* path,
1454+
double atime,
1455+
double mtime,
1456+
uv_fs_cb cb);
14501457
UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
14511458
uv_fs_t* req,
14521459
const char* path,

src/unix/fs.c

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,20 @@ static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
205205
}
206206

207207

208+
UV_UNUSED(static struct timespec uv__fs_to_timespec(double time)) {
209+
struct timespec ts;
210+
ts.tv_sec = time;
211+
ts.tv_nsec = (uint64_t)(time * 1000000) % 1000000 * 1000;
212+
return ts;
213+
}
214+
215+
UV_UNUSED(static struct timeval uv__fs_to_timeval(double time)) {
216+
struct timeval tv;
217+
tv.tv_sec = time;
218+
tv.tv_usec = (uint64_t)(time * 1000000) % 1000000;
219+
return tv;
220+
}
221+
208222
static ssize_t uv__fs_futime(uv_fs_t* req) {
209223
#if defined(__linux__) \
210224
|| defined(_AIX71) \
@@ -213,10 +227,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
213227
* for the sake of consistency with other platforms.
214228
*/
215229
struct timespec ts[2];
216-
ts[0].tv_sec = req->atime;
217-
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
218-
ts[1].tv_sec = req->mtime;
219-
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
230+
ts[0] = uv__fs_to_timespec(req->atime);
231+
ts[1] = uv__fs_to_timespec(req->mtime);
220232
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
221233
return utimensat(req->file, NULL, ts, 0);
222234
#else
@@ -230,10 +242,8 @@ static ssize_t uv__fs_futime(uv_fs_t* req) {
230242
|| defined(__OpenBSD__) \
231243
|| defined(__sun)
232244
struct timeval tv[2];
233-
tv[0].tv_sec = req->atime;
234-
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
235-
tv[1].tv_sec = req->mtime;
236-
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
245+
tv[0] = uv__fs_to_timeval(req->atime);
246+
tv[1] = uv__fs_to_timeval(req->mtime);
237247
# if defined(__sun)
238248
return futimesat(req->file, NULL, tv);
239249
# else
@@ -972,10 +982,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
972982
* for the sake of consistency with other platforms.
973983
*/
974984
struct timespec ts[2];
975-
ts[0].tv_sec = req->atime;
976-
ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
977-
ts[1].tv_sec = req->mtime;
978-
ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
985+
ts[0] = uv__fs_to_timespec(req->atime);
986+
ts[1] = uv__fs_to_timespec(req->mtime);
979987
return utimensat(AT_FDCWD, req->path, ts, 0);
980988
#elif defined(__APPLE__) \
981989
|| defined(__DragonFly__) \
@@ -984,10 +992,8 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
984992
|| defined(__NetBSD__) \
985993
|| defined(__OpenBSD__)
986994
struct timeval tv[2];
987-
tv[0].tv_sec = req->atime;
988-
tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
989-
tv[1].tv_sec = req->mtime;
990-
tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
995+
tv[0] = uv__fs_to_timeval(req->atime);
996+
tv[1] = uv__fs_to_timeval(req->mtime);
991997
return utimes(req->path, tv);
992998
#elif defined(_AIX) \
993999
&& !defined(_AIX71)
@@ -1010,6 +1016,31 @@ static ssize_t uv__fs_utime(uv_fs_t* req) {
10101016
}
10111017

10121018

1019+
static ssize_t uv__fs_lutime(uv_fs_t* req) {
1020+
#if defined(__linux__) || \
1021+
defined(_AIX71) || \
1022+
defined(__sun) || \
1023+
defined(__HAIKU__)
1024+
struct timespec ts[2];
1025+
ts[0] = uv__fs_to_timespec(req->atime);
1026+
ts[1] = uv__fs_to_timespec(req->mtime);
1027+
return utimensat(AT_FDCWD, req->path, ts, AT_SYMLINK_NOFOLLOW);
1028+
#elif defined(__APPLE__) || \
1029+
defined(__DragonFly__) || \
1030+
defined(__FreeBSD__) || \
1031+
defined(__FreeBSD_kernel__) || \
1032+
defined(__NetBSD__)
1033+
struct timeval tv[2];
1034+
tv[0] = uv__fs_to_timeval(req->atime);
1035+
tv[1] = uv__fs_to_timeval(req->mtime);
1036+
return lutimes(req->path, tv);
1037+
#else
1038+
errno = ENOSYS;
1039+
return -1;
1040+
#endif
1041+
}
1042+
1043+
10131044
static ssize_t uv__fs_write(uv_fs_t* req) {
10141045
#if defined(__linux__)
10151046
static int no_pwritev;
@@ -1523,6 +1554,7 @@ static void uv__fs_work(struct uv__work* w) {
15231554
X(FSYNC, uv__fs_fsync(req));
15241555
X(FTRUNCATE, ftruncate(req->file, req->off));
15251556
X(FUTIME, uv__fs_futime(req));
1557+
X(LUTIME, uv__fs_lutime(req));
15261558
X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
15271559
X(LINK, link(req->path, req->new_path));
15281560
X(MKDIR, mkdir(req->path, req->mode));
@@ -1709,6 +1741,19 @@ int uv_fs_futime(uv_loop_t* loop,
17091741
POST;
17101742
}
17111743

1744+
int uv_fs_lutime(uv_loop_t* loop,
1745+
uv_fs_t* req,
1746+
const char* path,
1747+
double atime,
1748+
double mtime,
1749+
uv_fs_cb cb) {
1750+
INIT(LUTIME);
1751+
PATH;
1752+
req->atime = atime;
1753+
req->mtime = mtime;
1754+
POST;
1755+
}
1756+
17121757

17131758
int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
17141759
INIT(LSTAT);

src/win/fs.c

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,34 +2225,68 @@ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
22252225
return 0;
22262226
}
22272227

2228-
2229-
static void fs__utime(uv_fs_t* req) {
2228+
INLINE static DWORD fs__utime_impl_from_path(WCHAR* path,
2229+
double atime,
2230+
double mtime,
2231+
int do_lutime) {
22302232
HANDLE handle;
2233+
DWORD flags;
2234+
DWORD ret;
22312235

2232-
handle = CreateFileW(req->file.pathw,
2236+
flags = FILE_FLAG_BACKUP_SEMANTICS;
2237+
if (do_lutime) {
2238+
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
2239+
}
2240+
2241+
handle = CreateFileW(path,
22332242
FILE_WRITE_ATTRIBUTES,
22342243
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
22352244
NULL,
22362245
OPEN_EXISTING,
2237-
FILE_FLAG_BACKUP_SEMANTICS,
2246+
flags,
22382247
NULL);
22392248

22402249
if (handle == INVALID_HANDLE_VALUE) {
2241-
SET_REQ_WIN32_ERROR(req, GetLastError());
2242-
return;
2250+
ret = GetLastError();
2251+
} else if (fs__utime_handle(handle, atime, mtime) != 0) {
2252+
ret = GetLastError();
2253+
} else {
2254+
ret = 0;
22432255
}
22442256

2245-
if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
2246-
SET_REQ_WIN32_ERROR(req, GetLastError());
2247-
CloseHandle(handle);
2257+
CloseHandle(handle);
2258+
return ret;
2259+
}
2260+
2261+
INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) {
2262+
DWORD error;
2263+
2264+
error = fs__utime_impl_from_path(req->file.pathw,
2265+
req->fs.time.atime,
2266+
req->fs.time.mtime,
2267+
do_lutime);
2268+
2269+
if (error != 0) {
2270+
if (do_lutime &&
2271+
(error == ERROR_SYMLINK_NOT_SUPPORTED ||
2272+
error == ERROR_NOT_A_REPARSE_POINT)) {
2273+
/* Opened file is a reparse point but not a symlink. Try again. */
2274+
fs__utime_impl(req, 0);
2275+
} else {
2276+
/* utime failed. */
2277+
SET_REQ_WIN32_ERROR(req, error);
2278+
}
2279+
22482280
return;
22492281
}
22502282

2251-
CloseHandle(handle);
2252-
22532283
req->result = 0;
22542284
}
22552285

2286+
static void fs__utime(uv_fs_t* req) {
2287+
fs__utime_impl(req, /* do_lutime */ 0);
2288+
}
2289+
22562290

22572291
static void fs__futime(uv_fs_t* req) {
22582292
int fd = req->file.fd;
@@ -2274,6 +2308,10 @@ static void fs__futime(uv_fs_t* req) {
22742308
req->result = 0;
22752309
}
22762310

2311+
static void fs__lutime(uv_fs_t* req) {
2312+
fs__utime_impl(req, /* do_lutime */ 1);
2313+
}
2314+
22772315

22782316
static void fs__link(uv_fs_t* req) {
22792317
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) {
26702708
XX(FTRUNCATE, ftruncate)
26712709
XX(UTIME, utime)
26722710
XX(FUTIME, futime)
2711+
XX(LUTIME, lutime)
26732712
XX(ACCESS, access)
26742713
XX(CHMOD, chmod)
26752714
XX(FCHMOD, fchmod)
@@ -3222,6 +3261,21 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
32223261
POST;
32233262
}
32243263

3264+
int uv_fs_lutime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
3265+
double mtime, uv_fs_cb cb) {
3266+
int err;
3267+
3268+
INIT(UV_FS_LUTIME);
3269+
err = fs__capture_path(req, path, NULL, cb != NULL);
3270+
if (err) {
3271+
return uv_translate_sys_error(err);
3272+
}
3273+
3274+
req->fs.time.atime = atime;
3275+
req->fs.time.mtime = mtime;
3276+
POST;
3277+
}
3278+
32253279

32263280
int uv_fs_statfs(uv_loop_t* loop,
32273281
uv_fs_t* req,

0 commit comments

Comments
 (0)